1 /* Check if pthread_atfork handler can call dlclose (BZ#24595).
2    Copyright (C) 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    <http://www.gnu.org/licenses/>.  */
18 
19 #include <stdio.h>
20 #include <pthread.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 
25 #include <support/check.h>
26 #include <support/xthread.h>
27 #include <support/capture_subprocess.h>
28 #include <support/xdlfcn.h>
29 
30 /* Check if pthread_atfork handlers do not deadlock when calling a function
31    that might alter the internal fork handle list, such as dlclose.
32 
33    The test registers a callback set with pthread_atfork(), dlopen() a shared
34    library (nptl/tst-atfork3mod.c), calls an exported symbol from the library
35    (which in turn also registers atfork handlers), and calls fork to trigger
36    the callbacks.  */
37 
38 static void *handler;
39 static bool run_dlclose_prepare;
40 static bool run_dlclose_parent;
41 static bool run_dlclose_child;
42 
43 static void
prepare(void)44 prepare (void)
45 {
46   if (run_dlclose_prepare)
47     xdlclose (handler);
48 }
49 
50 static void
parent(void)51 parent (void)
52 {
53   if (run_dlclose_parent)
54     xdlclose (handler);
55 }
56 
57 static void
child(void)58 child (void)
59 {
60   if (run_dlclose_child)
61     xdlclose (handler);
62 }
63 
64 static void
proc_func(void * closure)65 proc_func (void *closure)
66 {
67 }
68 
69 static void
do_test_generic(bool dlclose_prepare,bool dlclose_parent,bool dlclose_child)70 do_test_generic (bool dlclose_prepare, bool dlclose_parent, bool dlclose_child)
71 {
72   run_dlclose_prepare = dlclose_prepare;
73   run_dlclose_parent = dlclose_parent;
74   run_dlclose_child = dlclose_child;
75 
76   handler = xdlopen ("tst-atfork3mod.so", RTLD_NOW);
77 
78   int (*atfork3mod_func)(void);
79   atfork3mod_func = xdlsym (handler, "atfork3mod_func");
80 
81   atfork3mod_func ();
82 
83   struct support_capture_subprocess proc
84     = support_capture_subprocess (proc_func, NULL);
85   support_capture_subprocess_check (&proc, "tst-atfork3", 0, sc_allow_none);
86 
87   handler = atfork3mod_func = NULL;
88 
89   support_capture_subprocess_free (&proc);
90 }
91 
92 static void *
thread_func(void * closure)93 thread_func (void *closure)
94 {
95   return NULL;
96 }
97 
98 static int
do_test(void)99 do_test (void)
100 {
101   {
102     /* Make the process acts as multithread.  */
103     pthread_attr_t attr;
104     xpthread_attr_init (&attr);
105     xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
106     xpthread_create (&attr, thread_func, NULL);
107   }
108 
109   TEST_COMPARE (pthread_atfork (prepare, parent, child), 0);
110 
111   do_test_generic (true  /* prepare */, false /* parent */, false /* child */);
112   do_test_generic (false /* prepare */, true  /* parent */, false /* child */);
113   do_test_generic (false /* prepare */, false /* parent */, true  /* child */);
114 
115   return 0;
116 }
117 
118 #include <support/test-driver.c>
119