github.com/libunwind/libunwind/pull/831 github.com/libunwind/libunwind/commit/b67d508 From b67d508a93bf1ba231c18dce3894cfee25c16e0d Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Wed, 12 Feb 2025 12:08:07 -0500 Subject: [PATCH] Fix bad prototype for malloc() in test The unit test Gtest-nomalloc.c had an incorrect prototype for malloc() which caused newer compilers to fail compiling for newer C editions. Corrected the prototype and corrected a few other errors. The unit now compiles using GCC with `CFLAGS=-Wall -Wextra -pedantic -C11` with no warnings, which is the minimum requirement. Added the tests/unw_test.h header as a first step to cleaning up some unit tests further. --- tests/Gtest-nomalloc.c | 124 +++++++++++++++++++++++------------------ tests/Makefile.am | 2 +- tests/unw_test.h | 47 ++++++++++++++++ 3 files changed, 117 insertions(+), 56 deletions(-) create mode 100644 tests/unw_test.h diff --git a/tests/Gtest-nomalloc.c b/tests/Gtest-nomalloc.c index 5b97fc709..e770ff614 100644 --- a/tests/Gtest-nomalloc.c +++ b/tests/Gtest-nomalloc.c @@ -1,78 +1,92 @@ -/* libunwind - a platform-independent unwind library - Copyright (C) 2009 Google, Inc - Contributed by Arun Sharma +/** + * @file tests/Gtest-nomalloc.c + * + * Verify that @c malloc() is not called during an unwinding operation. + */ +/* + * This file is part of libunwind. + * Copyright 2025 Stephen M. Webb + * Copyright (C) 2009 Google, Inc + * Contributed by Arun Sharma + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#include -#include -#include #include #include +#include +#include +#include -#define panic(args...) \ - { fprintf (stderr, args); exit (-1); } +#include "unw_test.h" -int verbose; -int num_errors; +int malloc_call_count; int in_unwind; +/** + * Intercepted malloc() call. + * + * If invoked during unwinding this call will increment the test error count + * and indicate a failure by returning NULL. Otherwise it just calls the real + * malloc(). + */ void * -malloc(size_t s) +malloc (size_t sz) { - static void * (*func)(); + typedef void *(*malloc_t) (size_t); - if(!func) - func = (void *(*)()) dlsym(RTLD_NEXT, "malloc"); + static malloc_t real_malloc = NULL; + if (real_malloc == NULL) + { + real_malloc = (malloc_t)(intptr_t)dlsym (RTLD_NEXT, "malloc"); + if (real_malloc == NULL) + { + fprintf (stderr, "no malloc() found\n"); + exit (UNW_TEST_EXIT_HARD_ERROR); \ + } + } - if (in_unwind) { - num_errors++; - return NULL; - } else { - return func(s); - } + if (in_unwind) + { + malloc_call_count++; + } + return real_malloc (sz); } static void do_backtrace (void) { - unw_word_t ip, sp; - unw_cursor_t cursor; + unw_cursor_t cursor; unw_context_t uc; - int ret; + int ret; in_unwind = 1; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) - panic ("unw_init_local failed!\n"); + { + fprintf (stderr, "unw_init_local failed!\n"); + exit (UNW_TEST_EXIT_HARD_ERROR); \ + } do { - unw_get_reg (&cursor, UNW_REG_IP, &ip); - unw_get_reg (&cursor, UNW_REG_SP, &sp); - ret = unw_step (&cursor); - if (ret < 0) - { - ++num_errors; - } } while (ret > 0); in_unwind = 0; @@ -99,12 +113,12 @@ foo1 (void) int main (void) { - foo1(); + foo1 (); - if (num_errors > 0) + if (malloc_call_count > 0) { - fprintf (stderr, "FAILURE: detected %d errors\n", num_errors); - exit (-1); + fprintf (stderr, "FAILURE: malloc called %d times, expected 0\n", malloc_call_count); + exit (UNW_TEST_EXIT_FAIL); } - return 0; + exit (UNW_TEST_EXIT_PASS); } diff --git a/tests/Makefile.am b/tests/Makefile.am index adc34ac63..60f3f3adc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -214,7 +214,7 @@ endif noinst_PROGRAMS = $(noinst_PROGRAMS_common) $(noinst_PROGRAMS_cdep) \ $(noinst_PROGRAMS_arch) -noinst_HEADERS = ident.h +noinst_HEADERS = ident.h unw_test.h do_test_subst = sed -e 's,[@]TESTS[@],$(TESTS),g' \ -e 's,[@]XFAIL_TESTS[@],$(XFAIL_TESTS),g' \ diff --git a/tests/unw_test.h b/tests/unw_test.h new file mode 100644 index 000000000..9ae86dce1 --- /dev/null +++ b/tests/unw_test.h @@ -0,0 +1,47 @@ +/** + * @file tests/unw_test.h + * + * Common unit test API for libunwind. + */ +/* + * This file is part of libunwind. + * Copyright 2025 Stephen M. Webb + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef LIBUNWIND_UNW_TEST_H +#define LIBUNWIND_UNW_TEST_H 1 + +/** + * Exit values for test programs. + * Based on https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html + * + * These are used to interact with the test harness (eg. a TAP-based harness, + * CTest, or automake). + */ +enum { + UNW_TEST_EXIT_PASS = 0, /* Item under test is a PASS */ + UNW_TEST_EXIT_FAIL = 1, /* Item under test is a FAIL */ + UNW_TEST_EXIT_BAD_COMMAND = 2, /* Test program is invoked with invalid arguments */ + UNW_TEST_EXIT_SKIP = 77, /* Test should be skipped */ + UNW_TEST_EXIT_HARD_ERROR = 99 /* Test program itself has failed */ +}; + +#endif /* LIBUNWIND_UNW_TEST_H */ +