diff options
Diffstat (limited to 'assert/test-assert-2.c')
-rw-r--r-- | assert/test-assert-2.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/assert/test-assert-2.c b/assert/test-assert-2.c new file mode 100644 index 0000000..6d54ef9 --- /dev/null +++ b/assert/test-assert-2.c @@ -0,0 +1,167 @@ +/* Test assert's compliance with POSIX requirements. + Copyright (C) 2024-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* This test verifies that a failed assertion acts in accordance with + the POSIX requirements, despite any internal failures. We do so by + calling test routines via fork() and monitoring their exit codes + and stderr, while possibly forcing internal functions (malloc) to + fail. */ + +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> + +#undef NDEBUG +#include <assert.h> + +#include <support/check.h> +#include <support/support.h> +#include <support/capture_subprocess.h> +#include <support/xstdio.h> + +/* We need to be able to make malloc() "fail" so that __asprintf + fails. */ + +void * (*next_malloc)(size_t sz) = 0; +static volatile bool fail_malloc = 0; + +void * +malloc (size_t sz) +{ + if (fail_malloc) + return NULL; + if (next_malloc == 0) + next_malloc = dlsym (RTLD_NEXT, "malloc"); + if (next_malloc == 0) + return NULL; + return next_malloc (sz); +} + +/* We can tell if abort() is called by looking for the custom return + value. */ + +void +abort_handler(int s) +{ + _exit(5); +} + +static int do_lineno; +static const char *do_funcname; + +/* Hack to get the line of the assert. */ +#define GET_INFO_1(l) \ + if (closure != NULL) \ + { \ + do_lineno = l; \ + do_funcname = __func__; \ + return; \ + } +#define GET_INFO() GET_INFO_1(__LINE__+1) + +/* These are the two test cases. */ + +static void +test_assert_normal (void *closure) +{ + if (closure == NULL) + signal (SIGABRT, abort_handler); + + GET_INFO (); + assert (1 == 2); +} + + +static void +test_assert_nomalloc (void *closure) +{ + if (closure == NULL) + { + signal (SIGABRT, abort_handler); + fail_malloc = 1; + } + + GET_INFO (); + assert (1 == 2); +} + +static void +check_posix (const char *buf, int rv, int line, + const char *funcname, const char *testarg) +{ + /* POSIX requires that a failed assertion write a diagnostic to + stderr and call abort. The diagnostic must include the filename, + line number, and function where the assertion failed, along with + the text of the assert() argument. + */ + char linestr[100]; + + sprintf (linestr, "%d", line); + + /* If abort is called, our handler will return 5. */ + TEST_VERIFY (rv == 5); + + TEST_VERIFY (strstr (buf, __FILE__) != NULL); + TEST_VERIFY (strstr (buf, linestr) != NULL); + TEST_VERIFY (strstr (buf, funcname) != NULL); + TEST_VERIFY (strstr (buf, testarg) != NULL); + +} + +static void +one_test (void (*func)(void *), int which_path) +{ + struct support_capture_subprocess sp; + int rv; + + func (&do_lineno); + printf("running test for %s, line %d\n", do_funcname, do_lineno); + + sp = support_capture_subprocess (func, NULL); + rv = WEXITSTATUS (sp.status); + + check_posix (sp.err.buffer, rv, do_lineno, do_funcname, "1 == 2"); + + /* Look for intentional subtle differences in messages to verify + that the intended code path was taken. */ + switch (which_path) + { + case 0: + TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL); + break; + case 1: + TEST_VERIFY (strstr (sp.err.buffer, "failed\n") != NULL); + break; + } + + support_capture_subprocess_free (&sp); +} + +static int +do_test(void) +{ + one_test (test_assert_normal, 0); + one_test (test_assert_nomalloc, 1); + + return 0; +} + +#include <support/test-driver.c> |