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
29extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
30extern 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
38extern int atexit_alias (void (*) (void)) __asm__ ("atexit");
39extern int at_quick_exit_alias (void (*) (void)) __asm__ ("at_quick_exit");
40extern int on_exit_alias (void (*) (void), void *) __asm__ ("on_exit");
41
42
43static void
44test_bz20544_atexit (void *closure)
45{
46 atexit_alias (NULL); /* Should assert. */
47 exit (EXIT_FAILURE);
48}
49
50static void
51test_bz20544_at_quick_exit (void *closure)
52{
53 at_quick_exit_alias (NULL); /* Should assert. */
54 exit (EXIT_FAILURE);
55}
56
57static void
58test_bz20544_on_exit (void *closure)
59{
60 on_exit_alias (NULL, NULL); /* Should assert. */
61 exit (EXIT_FAILURE);
62}
63
64static void
65test_bz20544_cxa_atexit (void *closure)
66{
67 __cxa_atexit (NULL, NULL, NULL); /* Should assert. */
68 exit (EXIT_FAILURE);
69}
70
71static void
72test_bz20544_cxa_at_quick_exit (void *closure)
73{
74 __cxa_at_quick_exit (NULL, NULL, NULL); /* Should assert. */
75 exit (EXIT_FAILURE);
76}
77
78static void
79test_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 (callback: test_fn, NULL);
84 support_capture_subprocess_check (&result, context: "bz20544", status_or_signal: -SIGABRT,
85 allowed: sc_allow_stderr);
86
87 if (strstr (result.err.buffer, expected_error) == NULL)
88 {
89 support_record_failure ();
90 printf (format: "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
99static int
100do_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_fn: test_bz20544_atexit);
107 test_one_fn (test_fn: test_bz20544_at_quick_exit);
108 test_one_fn (test_fn: test_bz20544_on_exit);
109 test_one_fn (test_fn: test_bz20544_cxa_atexit);
110 test_one_fn (test_fn: test_bz20544_cxa_at_quick_exit);
111
112 return 0;
113}
114
115#include <support/test-driver.c>
116

source code of glibc/stdlib/tst-bz20544.c