1 /* Helper file for tst-{atexit,at_quick_exit,cxa_atexit,on_exit}.
2    Copyright (C) 2017-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 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/wait.h>
25 
26 /* http://pubs.opengroup.org/onlinepubs/000095399/functions/atexit.html
27    requires that we support at least 32 atexit handlers.
28 
29    The number we actually support is limited by memory. Here we simply
30    check that we support at least the minimum required.  */
31 #define MAX_ATEXIT 32
32 
33 /* Arbitrary sequence matching current registrations.  */
34 const char expected[] = "00000000000000000000000003021121130211";
35 
36 static char crumbs[sizeof (expected)];
37 static int next_slot = 0;
38 
39 /* Helper: flush stdout and _exit.  */
40 static void
_exit_with_flush(int code)41 _exit_with_flush (int code)
42 {
43   fflush (stdout);
44   _exit (code);
45 }
46 
47 static void
fn0(void)48 fn0 (void)
49 {
50   crumbs[next_slot++] = '0';
51 }
52 
53 static void
fn1(void)54 fn1 (void)
55 {
56   crumbs[next_slot++] = '1';
57 }
58 
59 static void
fn2(void)60 fn2 (void)
61 {
62   crumbs[next_slot++] = '2';
63   ATEXIT (fn1);
64 }
65 
66 static void
fn3(void)67 fn3 (void)
68 {
69   crumbs[next_slot++] = '3';
70   ATEXIT (fn2);
71   ATEXIT (fn0);
72 }
73 
74 static void
fn_final(void)75 fn_final (void)
76 {
77   if (strcmp (crumbs, expected) == 0)
78     _exit_with_flush (0);
79 
80   printf ("crumbs:   %s\n", crumbs);
81   printf ("expected: %s\n", expected);
82   _exit_with_flush (1);
83 }
84 
85 static int
do_test(void)86 do_test (void)
87 {
88   int slots_remaining = MAX_ATEXIT;
89 
90   /* Register this first so it can verify expected order of the rest.  */
91   ATEXIT (fn_final); --slots_remaining;
92 
93   ATEXIT (fn1); --slots_remaining;
94   ATEXIT (fn3); --slots_remaining;
95   ATEXIT (fn1); --slots_remaining;
96   ATEXIT (fn2); --slots_remaining;
97   ATEXIT (fn1); --slots_remaining;
98   ATEXIT (fn3); --slots_remaining;
99 
100   /* Fill the rest of available slots with fn0.  */
101   while (slots_remaining > 0)
102     {
103       ATEXIT (fn0); --slots_remaining;
104     }
105 
106   /* Verify that handlers registered above are inherited across fork.  */
107   const pid_t child = fork ();
108   switch (child)
109     {
110     case -1:
111       printf ("fork: %m\n");
112       _exit_with_flush (3);
113     case 0:  /* Child.  */
114       break;
115     default:
116       {
117 	int status;
118 	const pid_t exited = waitpid (child, &status, 0);
119 	if (child != exited)
120 	  {
121 	    printf ("unexpected child: %d, expected %d\n", exited, child);
122 	    _exit_with_flush (4);
123 	  }
124 	if (status != 0)
125 	  {
126 	    if (WIFEXITED (status))
127 	      printf ("unexpected exit status %d from child %d\n",
128 		      WEXITSTATUS (status), child);
129 	    else if (WIFSIGNALED (status))
130 	      printf ("unexpected signal %d from child %d\n",
131 		      WTERMSIG (status), child);
132 	    else
133 	      printf ("unexpected status %d from child %d\n", status, child);
134 	    _exit_with_flush (5);
135 	  }
136       }
137       break;
138     }
139 
140   EXIT (2);  /* If we see this exit code, fn_final must have not worked.  */
141 }
142 
143 #define TEST_FUNCTION do_test
144 #include <support/test-driver.c>
145