Remove 'grp' and merge into 'nss' and 'posix'
[platform/upstream/glibc.git] / stdlib / tst-atexit-common.c
1 /* Helper file for tst-{atexit,at_quick_exit,cxa_atexit,on_exit}.
2    Copyright (C) 2017-2023 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
41 _exit_with_flush (int code)
42 {
43   fflush (stdout);
44   _exit (code);
45 }
46
47 static void
48 fn0 (void)
49 {
50   crumbs[next_slot++] = '0';
51 }
52
53 static void
54 fn1 (void)
55 {
56   crumbs[next_slot++] = '1';
57 }
58
59 static void
60 fn2 (void)
61 {
62   crumbs[next_slot++] = '2';
63   ATEXIT (fn1);
64 }
65
66 static void
67 fn3 (void)
68 {
69   crumbs[next_slot++] = '3';
70   ATEXIT (fn2);
71   ATEXIT (fn0);
72 }
73
74 static 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
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>