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
38static void *handler;
39static bool run_dlclose_prepare;
40static bool run_dlclose_parent;
41static bool run_dlclose_child;
42
43static void
44prepare (void)
45{
46 if (run_dlclose_prepare)
47 xdlclose (handle: handler);
48}
49
50static void
51parent (void)
52{
53 if (run_dlclose_parent)
54 xdlclose (handle: handler);
55}
56
57static void
58child (void)
59{
60 if (run_dlclose_child)
61 xdlclose (handle: handler);
62}
63
64static void
65proc_func (void *closure)
66{
67}
68
69static void
70do_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
92static void *
93thread_func (void *closure)
94{
95 return NULL;
96}
97
98static int
99do_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

source code of glibc/sysdeps/pthread/tst-atfork3.c