1/* _dl_find_object test with parallelism.
2 Copyright (C) 2021-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 <https://www.gnu.org/licenses/>. */
18
19#include <array_length.h>
20#include <dlfcn.h>
21#include <elf/dl-find_object.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <support/check.h>
25#include <support/support.h>
26#include <support/xdlfcn.h>
27#include <support/xthread.h>
28#include <support/xunistd.h>
29
30/* Computes the expected _dl_find_object result directly from the
31 map. */
32static void
33from_map (struct link_map *l, struct dl_find_object *expected)
34{
35 struct dl_find_object_internal internal;
36 _dl_find_object_from_map (l, result: &internal);
37 _dl_find_object_to_external (internal: &internal, external: expected);
38}
39
40/* Returns the soname for the test object NUMBER. */
41static char *
42soname (int number)
43{
44 return xasprintf (format: "tst-dl_find_object-mod%d.so", number);
45}
46
47/* Returns the data symbol name for the test object NUMBER. */
48static char *
49symbol (int number)
50{
51 return xasprintf (format: "mod%d_data", number);
52}
53
54struct verify_data
55{
56 char *soname;
57 void *address; /* Address in the shared object. */
58 struct dl_find_object dlfo;
59 pthread_t thr;
60};
61
62/* Compare _dl_find_object result at ADDRESS with *EXPECTED. */
63static void
64check (void *address, struct dl_find_object *expected, int line)
65{
66 struct dl_find_object actual;
67 int ret = _dl_find_object (address: address, result: &actual);
68 if (expected == NULL)
69 {
70 if (ret != -1)
71 {
72 support_record_failure ();
73 printf (format: "%s:%d: unexpected success for %p\n",
74 __FILE__, line, address);
75 }
76 return;
77 }
78 if (ret != 0)
79 {
80 support_record_failure ();
81 printf (format: "%s:%d: unexpected failure for %p\n",
82 __FILE__, line, address);
83 return;
84 }
85
86 if (actual.dlfo_flags != expected->dlfo_flags)
87 {
88 support_record_failure ();
89 printf (format: "%s:%d: error: %p: flags is %llu, expected %llu\n",
90 __FILE__, line, address,
91 actual.dlfo_flags, expected->dlfo_flags);
92 }
93 if (actual.dlfo_flags != expected->dlfo_flags)
94 {
95 support_record_failure ();
96 printf (format: "%s:%d: error: %p: map start is %p, expected %p\n",
97 __FILE__, line,
98 address, actual.dlfo_map_start, expected->dlfo_map_start);
99 }
100 if (actual.dlfo_map_end != expected->dlfo_map_end)
101 {
102 support_record_failure ();
103 printf (format: "%s:%d: error: %p: map end is %p, expected %p\n",
104 __FILE__, line,
105 address, actual.dlfo_map_end, expected->dlfo_map_end);
106 }
107 if (actual.dlfo_link_map != expected->dlfo_link_map)
108 {
109 support_record_failure ();
110 printf (format: "%s:%d: error: %p: link map is %p, expected %p\n",
111 __FILE__, line,
112 address, actual.dlfo_link_map, expected->dlfo_link_map);
113 }
114 if (actual.dlfo_eh_frame != expected->dlfo_eh_frame)
115 {
116 support_record_failure ();
117 printf (format: "%s:%d: error: %p: EH frame is %p, expected %p\n",
118 __FILE__, line,
119 address, actual.dlfo_eh_frame, expected->dlfo_eh_frame);
120 }
121#if DLFO_STRUCT_HAS_EH_DBASE
122 if (actual.dlfo_eh_dbase != expected->dlfo_eh_dbase)
123 {
124 support_record_failure ();
125 printf ("%s:%d: error: %p: data base is %p, expected %p\n",
126 __FILE__, line,
127 address, actual.dlfo_eh_dbase, expected->dlfo_eh_dbase);
128 }
129#endif
130#if DLFO_STRUCT_HAS_EH_COUNT
131 if (actual.dlfo_eh_count != expected->dlfo_eh_count)
132 {
133 support_record_failure ();
134 printf ("%s:%d: error: %p: count is %d, expected %d\n",
135 __FILE__, line,
136 address, actual.dlfo_eh_count, expected->dlfo_eh_count);
137 }
138#endif
139}
140
141/* Request process termination after 0.3 seconds. */
142static bool exit_requested;
143static void *
144exit_thread (void *ignored)
145{
146 usleep (useconds: 300 * 1000);
147 __atomic_store_n (&exit_requested, true, __ATOMIC_RELAXED);
148 return NULL;
149}
150
151static void *
152verify_thread (void *closure)
153{
154 struct verify_data *data = closure;
155
156 while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
157 {
158 check (address: data->address, expected: &data->dlfo, __LINE__);
159 check (address: data->dlfo.dlfo_map_start, expected: &data->dlfo, __LINE__);
160 check (address: data->dlfo.dlfo_map_end - 1, expected: &data->dlfo, __LINE__);
161 }
162
163 return NULL;
164}
165
166/* Sets up the verification data, dlopen'ing shared object NUMBER, and
167 launches a verification thread. */
168static void
169start_verify (int number, struct verify_data *data)
170{
171 data->soname = soname (number);
172 struct link_map *l = xdlopen (filename: data->soname, RTLD_NOW);
173 from_map (l, expected: &data->dlfo);
174 TEST_VERIFY_EXIT (data->dlfo.dlfo_link_map == l);
175 char *sym = symbol (number);
176 data->address = xdlsym (handle: data->dlfo.dlfo_link_map, symbol: sym);
177 free (ptr: sym);
178 data->thr = xpthread_create (NULL, thread_func: verify_thread, closure: data);
179}
180
181
182static int
183do_test (void)
184{
185 struct verify_data data_mod2;
186 struct verify_data data_mod4;
187 struct verify_data data_mod7;
188
189 /* Load the modules with gaps. */
190 {
191 void *mod1 = xdlopen (filename: "tst-dl_find_object-mod1.so", RTLD_NOW);
192 start_verify (number: 2, data: &data_mod2);
193 void *mod3 = xdlopen (filename: "tst-dl_find_object-mod3.so", RTLD_NOW);
194 start_verify (number: 4, data: &data_mod4);
195 void *mod5 = xdlopen (filename: "tst-dl_find_object-mod5.so", RTLD_NOW);
196 void *mod6 = xdlopen (filename: "tst-dl_find_object-mod6.so", RTLD_NOW);
197 start_verify (number: 7, data: &data_mod7);
198 xdlclose (handle: mod6);
199 xdlclose (handle: mod5);
200 xdlclose (handle: mod3);
201 xdlclose (handle: mod1);
202 }
203
204 /* Objects that continuously opened and closed. */
205 struct temp_object
206 {
207 char *soname;
208 char *symbol;
209 struct link_map *link_map;
210 void *address;
211 } temp_objects[] =
212 {
213 { soname (number: 1), symbol (number: 1), },
214 { soname (number: 3), symbol (number: 3), },
215 { soname (number: 5), symbol (number: 5), },
216 { soname (number: 6), symbol (number: 6), },
217 { soname (number: 8), symbol (number: 8), },
218 { soname (number: 9), symbol (number: 9), },
219 };
220
221 pthread_t exit_thr = xpthread_create (NULL, thread_func: exit_thread, NULL);
222
223 struct drand48_data state;
224 srand48_r (seedval: 1, buffer: &state);
225 while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
226 {
227 long int idx;
228 lrand48_r (buffer: &state, result: &idx);
229 idx %= array_length (temp_objects);
230 if (temp_objects[idx].link_map == NULL)
231 {
232 temp_objects[idx].link_map = xdlopen (filename: temp_objects[idx].soname,
233 RTLD_NOW);
234 temp_objects[idx].address = xdlsym (handle: temp_objects[idx].link_map,
235 symbol: temp_objects[idx].symbol);
236 }
237 else
238 {
239 xdlclose (handle: temp_objects[idx].link_map);
240 temp_objects[idx].link_map = NULL;
241 struct dl_find_object dlfo;
242 int ret = _dl_find_object (address: temp_objects[idx].address, result: &dlfo);
243 if (ret != -1)
244 {
245 TEST_VERIFY_EXIT (ret == 0);
246 support_record_failure ();
247 printf (format: "%s: error: %s EH found after dlclose, link map %p\n",
248 __FILE__, temp_objects[idx].soname, dlfo.dlfo_link_map);
249 }
250 }
251 }
252
253 xpthread_join (thr: data_mod2.thr);
254 xpthread_join (thr: data_mod4.thr);
255 xpthread_join (thr: data_mod7.thr);
256 xpthread_join (thr: exit_thr);
257
258 for (size_t i = 0; i < array_length (temp_objects); ++i)
259 {
260 free (ptr: temp_objects[i].soname);
261 free (ptr: temp_objects[i].symbol);
262 if (temp_objects[i].link_map != NULL)
263 xdlclose (handle: temp_objects[i].link_map);
264 }
265
266 free (ptr: data_mod2.soname);
267 free (ptr: data_mod4.soname);
268 xdlclose (handle: data_mod4.dlfo.dlfo_link_map);
269 free (ptr: data_mod7.soname);
270 xdlclose (handle: data_mod7.dlfo.dlfo_link_map);
271
272 return 0;
273}
274
275#include <support/test-driver.c>
276

source code of glibc/elf/tst-dl_find_object-threads.c