1 /* Test for shm_open cancellation handling: BZ #18243.
2    Copyright (C) 2016-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 <pthread.h>
20 #include <sys/mman.h>
21 #include <semaphore.h>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 
28 static sem_t sem;	/* Use to sync with thread start.  */
29 static char shm_name[sizeof "/glibc-shm_open-cancel-" + sizeof (pid_t) * 3];
30 
31 static void
init_shm_name(void)32 init_shm_name (void)
33 {
34   snprintf (shm_name, sizeof (shm_name), "/glibc-shm_open-cancel-%u",
35 	    getpid ());
36 }
37 
38 static void
remove_shm(int status,void * arg)39 remove_shm (int status, void *arg)
40 {
41   shm_unlink (shm_name);
42 }
43 
44 static void *
tf(void * arg)45 tf (void *arg)
46 {
47   pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, 0);
48 
49   if (sem_wait (&sem) != 0)
50     {
51       printf ("error: sem_wait failed: %m");
52       exit (1);
53     }
54 
55   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0) != 0)
56     {
57       printf ("error: pthread_setcancelstate failed: %m");
58       exit (1);
59     }
60 
61   /* Neither sem_unlink or sem_open should act on thread cancellation.  */
62   shm_unlink (shm_name);
63   on_exit (remove_shm, NULL);
64 
65   int fd = shm_open (shm_name, O_CREAT, 0600);
66   if (fd == -1)
67     {
68       int exit_code;
69       if (errno == ENOSYS || errno == EACCES)
70 	exit_code = 77;
71       else
72 	exit_code = 1;
73       exit (exit_code);
74     }
75 
76   if (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, 0) != 0)
77     {
78       printf ("error: pthread_setcancelstate failed: %m");
79       exit (1);
80     }
81 
82   if (close (fd) != 0)
83     {
84       printf ("error: pthread_setcancelstate failed: %m");
85       exit (1);
86     }
87 
88   return NULL;
89 }
90 
91 static int
do_test(void)92 do_test (void)
93 {
94   pthread_t td;
95 
96   init_shm_name ();
97 
98   if (sem_init (&sem, 0, 0))
99     {
100       printf ("error: sem_init failed: %m\n");
101       exit (1);
102     }
103 
104   if (pthread_create (&td, NULL, tf, NULL) != 0)
105     {
106       printf ("error: pthread_create failed: %m\n");
107       exit (1);
108     }
109 
110   if (pthread_cancel (td) != 0)
111     {
112       printf ("error: pthread_cancel failed: %m\n");
113       exit (1);
114     }
115 
116   if (sem_post (&sem) != 0)
117     {
118       printf ("error: sem_post failed: %m\n");
119       exit (1);
120     }
121 
122   void *r;
123   if (pthread_join (td, &r) != 0)
124     {
125       printf ("error: pthread_join failed: %m\n");
126       exit (1);
127     }
128 
129   if (r == PTHREAD_CANCELED)
130     {
131       puts ("error: pthread_join returned PTHREAD_CANCELED");
132       exit (1);
133     }
134 
135   return 0;
136 }
137 
138 #define TEST_FUNCTION do_test ()
139 #include <test-skeleton.c>
140