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