1 /* Verify atexit, on_exit, etc. abort on NULL function pointer.
2 Copyright (C) 2018-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19
20 #include <assert.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <support/capture_subprocess.h>
25 #include <support/check.h>
26 #include <support/support.h>
27 #include <support/test-driver.h>
28
29 extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
30 extern int __cxa_at_quick_exit (void (*func) (void *), void *arg, void *d);
31
32 /* GCC "knows" that atexit and on_exit should not be called with NULL
33 function pointer, and emits diagnostics if we try to do so.
34 Presumably it could emit a trap and drop the call altogether.
35
36 The aliases below are intended to bypass this. */
37
38 extern int atexit_alias (void (*) (void)) __asm__ ("atexit");
39 extern int at_quick_exit_alias (void (*) (void)) __asm__ ("at_quick_exit");
40 extern int on_exit_alias (void (*) (void), void *) __asm__ ("on_exit");
41
42
43 static void
test_bz20544_atexit(void * closure)44 test_bz20544_atexit (void *closure)
45 {
46 atexit_alias (NULL); /* Should assert. */
47 exit (EXIT_FAILURE);
48 }
49
50 static void
test_bz20544_at_quick_exit(void * closure)51 test_bz20544_at_quick_exit (void *closure)
52 {
53 at_quick_exit_alias (NULL); /* Should assert. */
54 exit (EXIT_FAILURE);
55 }
56
57 static void
test_bz20544_on_exit(void * closure)58 test_bz20544_on_exit (void *closure)
59 {
60 on_exit_alias (NULL, NULL); /* Should assert. */
61 exit (EXIT_FAILURE);
62 }
63
64 static void
test_bz20544_cxa_atexit(void * closure)65 test_bz20544_cxa_atexit (void *closure)
66 {
67 __cxa_atexit (NULL, NULL, NULL); /* Should assert. */
68 exit (EXIT_FAILURE);
69 }
70
71 static void
test_bz20544_cxa_at_quick_exit(void * closure)72 test_bz20544_cxa_at_quick_exit (void *closure)
73 {
74 __cxa_at_quick_exit (NULL, NULL, NULL); /* Should assert. */
75 exit (EXIT_FAILURE);
76 }
77
78 static void
test_one_fn(void (* test_fn)(void *))79 test_one_fn (void (*test_fn) (void *))
80 {
81 const char expected_error[] = "Assertion `func != NULL' failed.\n";
82 struct support_capture_subprocess result;
83 result = support_capture_subprocess (test_fn, NULL);
84 support_capture_subprocess_check (&result, "bz20544", -SIGABRT,
85 sc_allow_stderr);
86
87 if (strstr (result.err.buffer, expected_error) == NULL)
88 {
89 support_record_failure ();
90 printf ("Did not find expected string in error output:\n"
91 " expected: >>>%s<<<\n"
92 " actual: >>>%s<<<\n",
93 expected_error, result.err.buffer);
94 }
95
96 support_capture_subprocess_free (&result);
97 }
98
99 static int
do_test(void)100 do_test (void)
101 {
102 #if defined (NDEBUG)
103 FAIL_UNSUPPORTED ("Assertions disabled (NDEBUG). "
104 "Can't verify that assertions fire.");
105 #endif
106 test_one_fn (test_bz20544_atexit);
107 test_one_fn (test_bz20544_at_quick_exit);
108 test_one_fn (test_bz20544_on_exit);
109 test_one_fn (test_bz20544_cxa_atexit);
110 test_one_fn (test_bz20544_cxa_at_quick_exit);
111
112 return 0;
113 }
114
115 #include <support/test-driver.c>
116