1 /* Copyright (C) 2003-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 
27 static int fd[4];
28 static pthread_barrier_t b;
29 volatile int in_sh_body;
30 unsigned long cleanups;
31 
32 static void
cl(void * arg)33 cl (void *arg)
34 {
35   cleanups = (cleanups << 4) | (long) arg;
36 }
37 
38 
39 static void __attribute__((noinline))
sh_body(void)40 sh_body (void)
41 {
42   char c;
43 
44   pthread_cleanup_push (cl, (void *) 1L);
45 
46   in_sh_body = 1;
47   if (read (fd[2], &c, 1) == 1)
48     {
49       puts ("read succeeded");
50       exit (1);
51     }
52 
53   pthread_cleanup_pop (0);
54 }
55 
56 
57 static void
sh(int sig)58 sh (int sig)
59 {
60   pthread_cleanup_push (cl, (void *) 2L);
61   sh_body ();
62   in_sh_body = 0;
63 
64   pthread_cleanup_pop (0);
65 }
66 
67 
68 static void __attribute__((noinline))
tf_body(void)69 tf_body (void)
70 {
71   char c;
72 
73   pthread_cleanup_push (cl, (void *) 3L);
74 
75   int r = pthread_barrier_wait (&b);
76   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
77     {
78       puts ("child thread: barrier_wait failed");
79       exit (1);
80     }
81 
82   if (read (fd[0], &c, 1) == 1)
83     {
84       puts ("read succeeded");
85       exit (1);
86     }
87 
88   read (fd[0], &c, 1);
89 
90   pthread_cleanup_pop (0);
91 }
92 
93 
94 static void *
tf(void * arg)95 tf (void *arg)
96 {
97   pthread_t th = (pthread_t) arg;
98 
99   int r = pthread_barrier_wait (&b);
100   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
101     {
102       puts ("parent thread: barrier_wait failed");
103       exit (1);
104     }
105 
106   sleep (1);
107 
108   r = pthread_kill (th, SIGHUP);
109   if (r)
110     {
111       errno = r;
112       printf ("pthread_kill failed %m\n");
113       exit (1);
114     }
115 
116   while (in_sh_body == 0)
117     sleep (1);
118 
119   if (pthread_cancel (th) != 0)
120     {
121       puts ("cancel failed");
122       exit (1);
123     }
124 
125   void *ret;
126   if (pthread_join (th, &ret) != 0)
127     {
128       puts ("join failed");
129       exit (1);
130     }
131 
132   if (ret != PTHREAD_CANCELED)
133     {
134       puts ("result is wrong");
135       exit (1);
136     }
137 
138   if (cleanups != 0x1234L)
139     {
140       printf ("called cleanups %lx\n", cleanups);
141       exit (1);
142     }
143 
144   if (pthread_barrier_destroy (&b))
145     {
146       puts ("barrier destroy failed");
147       exit (1);
148     }
149 
150   /* The pipe closing must be issued after the cancellation handling to avoid
151      a race condition where the cancellation runs after both pipe ends are
152      closed.  In this case the read syscall returns EOF and the cancellation
153      must not act.  */
154   close (fd[0]);
155   close (fd[1]);
156   close (fd[2]);
157   close (fd[3]);
158 
159   exit (0);
160 }
161 
162 
163 static int
do_one_test(void)164 do_one_test (void)
165 {
166   in_sh_body = 0;
167 
168   pid_t pid = fork ();
169 
170   if (pid == -1)
171     {
172       printf ("fork failed: %m\n");
173       return 1;
174     }
175 
176   if (pid)
177     {
178       int status;
179       if (waitpid (pid, &status, 0) < 0)
180 	{
181 	  printf ("waitpid failed %m\n");
182 	  return 1;
183 	}
184 
185       return !WIFEXITED (status) || WEXITSTATUS (status);
186     }
187 
188   if (pthread_barrier_init (&b, NULL, 2) != 0)
189     {
190       puts ("barrier_init failed");
191       exit (1);
192     }
193 
194   cleanups = 0;
195   if (pipe (fd) != 0 || pipe (fd + 2) != 0)
196     {
197       puts ("pipe failed");
198       exit (1);
199     }
200 
201   pthread_t th;
202   if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
203     {
204       puts ("create failed");
205       exit (1);
206     }
207 
208   pthread_cleanup_push (cl, (void *) 4L);
209   tf_body ();
210   pthread_cleanup_pop (0);
211   exit (1);
212 }
213 
214 
215 static int
do_test(void)216 do_test (void)
217 {
218   stack_t ss;
219   ss.ss_sp = malloc (2 * SIGSTKSZ);
220   if (ss.ss_sp == NULL)
221     {
222       puts ("failed to allocate alternate stack");
223       return 1;
224     }
225   ss.ss_flags = 0;
226   ss.ss_size = 2 * SIGSTKSZ;
227   if (sigaltstack (&ss, NULL) < 0)
228     {
229       printf ("sigaltstack failed %m\n");
230       return 1;
231     }
232 
233   struct sigaction sa;
234   sa.sa_handler = sh;
235   sigemptyset (&sa.sa_mask);
236   sa.sa_flags = 0;
237 
238   if (sigaction (SIGHUP, &sa, NULL) != 0)
239     {
240       puts ("sigaction failed");
241       return 1;
242     }
243 
244   puts ("sa_flags = 0 test");
245   if (do_one_test ())
246     return 1;
247 
248   sa.sa_handler = sh;
249   sigemptyset (&sa.sa_mask);
250   sa.sa_flags = SA_ONSTACK;
251 
252   if (sigaction (SIGHUP, &sa, NULL) != 0)
253     {
254       puts ("sigaction failed");
255       return 1;
256     }
257 
258   puts ("sa_flags = SA_ONSTACK test");
259   if (do_one_test ())
260     return 1;
261 
262 #ifdef SA_SIGINFO
263   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
264   sigemptyset (&sa.sa_mask);
265   sa.sa_flags = SA_SIGINFO;
266 
267   if (sigaction (SIGHUP, &sa, NULL) != 0)
268     {
269       puts ("sigaction failed");
270       return 1;
271     }
272 
273   puts ("sa_flags = SA_SIGINFO test");
274   if (do_one_test ())
275     return 1;
276 
277   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
278   sigemptyset (&sa.sa_mask);
279   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
280 
281   if (sigaction (SIGHUP, &sa, NULL) != 0)
282     {
283       puts ("sigaction failed");
284       return 1;
285     }
286 
287   puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
288   if (do_one_test ())
289     return 1;
290 #endif
291 
292   return 0;
293 }
294 
295 #define TIMEOUT 40
296 #define TEST_FUNCTION do_test ()
297 #include "../test-skeleton.c"
298