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