1 | /* Check if pthread_atfork handler can call dlclose (BZ#24595). |
2 | Copyright (C) 2022-2024 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 |
44 | prepare (void) |
45 | { |
46 | if (run_dlclose_prepare) |
47 | xdlclose (handle: handler); |
48 | } |
49 | |
50 | static void |
51 | parent (void) |
52 | { |
53 | if (run_dlclose_parent) |
54 | xdlclose (handle: handler); |
55 | } |
56 | |
57 | static void |
58 | child (void) |
59 | { |
60 | if (run_dlclose_child) |
61 | xdlclose (handle: handler); |
62 | } |
63 | |
64 | static void |
65 | proc_func (void *closure) |
66 | { |
67 | } |
68 | |
69 | static void |
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 (filename: "tst-atfork3mod.so" , RTLD_NOW); |
77 | |
78 | int (*atfork3mod_func)(void); |
79 | atfork3mod_func = xdlsym (handle: handler, symbol: "atfork3mod_func" ); |
80 | |
81 | atfork3mod_func (); |
82 | |
83 | struct support_capture_subprocess proc |
84 | = support_capture_subprocess (callback: proc_func, NULL); |
85 | support_capture_subprocess_check (&proc, context: "tst-atfork3" , status_or_signal: 0, allowed: sc_allow_none); |
86 | |
87 | handler = atfork3mod_func = NULL; |
88 | |
89 | support_capture_subprocess_free (&proc); |
90 | } |
91 | |
92 | static void * |
93 | thread_func (void *closure) |
94 | { |
95 | return NULL; |
96 | } |
97 | |
98 | static int |
99 | do_test (void) |
100 | { |
101 | { |
102 | /* Make the process acts as multithread. */ |
103 | pthread_attr_t attr; |
104 | xpthread_attr_init (attr: &attr); |
105 | xpthread_attr_setdetachstate (attr: &attr, PTHREAD_CREATE_DETACHED); |
106 | xpthread_create (attr: &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 | |