1 | /* Test dtv setup if entries don't have monotone increasing generation. |
2 | Copyright (C) 2021-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 <array_length.h> |
20 | #include <dlfcn.h> |
21 | #include <pthread.h> |
22 | #include <stdbool.h> |
23 | #include <stdint.h> |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <support/check.h> |
27 | #include <support/support.h> |
28 | #include <support/test-driver.h> |
29 | #include <support/xdlfcn.h> |
30 | #include <support/xthread.h> |
31 | |
32 | #define NMOD 100 |
33 | static void *mod[NMOD]; |
34 | |
35 | static void |
36 | load_fail (void) |
37 | { |
38 | /* Expected to fail because of a missing symbol. */ |
39 | void *m = dlopen (file: "tst-tls20mod-bad.so" , RTLD_NOW); |
40 | if (m != NULL) |
41 | FAIL_EXIT1 ("dlopen of tst-tls20mod-bad.so succeeded\n" ); |
42 | } |
43 | |
44 | static void |
45 | load_mod (int i) |
46 | { |
47 | char *buf = xasprintf (format: "tst-tls-manydynamic%02dmod.so" , i); |
48 | mod[i] = xdlopen (filename: buf, RTLD_LAZY); |
49 | free (ptr: buf); |
50 | } |
51 | |
52 | static void |
53 | unload_mod (int i) |
54 | { |
55 | if (mod[i] != NULL) |
56 | xdlclose (handle: mod[i]); |
57 | mod[i] = NULL; |
58 | } |
59 | |
60 | static void |
61 | access (int i) |
62 | { |
63 | char *buf = xasprintf (format: "tls_global_%02d" , i); |
64 | dlerror (); |
65 | int *p = dlsym (handle: mod[i], name: buf); |
66 | if (test_verbose) |
67 | printf (format: "mod[%d]: &tls = %p\n" , i, p); |
68 | if (p == NULL) |
69 | FAIL_EXIT1 ("dlsym failed: %s\n" , dlerror ()); |
70 | TEST_COMPARE (*p, 0); |
71 | ++*p; |
72 | free (ptr: buf); |
73 | } |
74 | |
75 | static void |
76 | access_mod (const char *modname, void *mod, int i) |
77 | { |
78 | char *modsym = xasprintf (format: "tls_global_%d" , i); |
79 | dlerror (); |
80 | int *p = dlsym (handle: mod, name: modsym); |
81 | if (test_verbose) |
82 | printf (format: "%s: &tls = %p\n" , modname, p); |
83 | if (p == NULL) |
84 | FAIL_EXIT1 ("dlsym failed: %s\n" , dlerror ()); |
85 | TEST_COMPARE (*p, 0); |
86 | ++*p; |
87 | free (ptr: modsym); |
88 | } |
89 | |
90 | static void |
91 | access_dep (int i) |
92 | { |
93 | char *modname = xasprintf (format: "tst-tls-manydynamic%dmod-dep.so" , i); |
94 | void *moddep = xdlopen (filename: modname, RTLD_LAZY); |
95 | access_mod (modname, mod: moddep, i); |
96 | free (ptr: modname); |
97 | xdlclose (handle: moddep); |
98 | } |
99 | |
100 | struct start_args |
101 | { |
102 | const char *modname; |
103 | void *mod; |
104 | int modi; |
105 | int ndeps; |
106 | const int *deps; |
107 | }; |
108 | |
109 | static void * |
110 | start (void *a) |
111 | { |
112 | struct start_args *args = a; |
113 | |
114 | for (int i = 0; i < NMOD; i++) |
115 | if (mod[i] != NULL) |
116 | access (i); |
117 | |
118 | if (args != NULL) |
119 | { |
120 | access_mod (modname: args->modname, mod: args->mod, i: args->modi); |
121 | for (int n = 0; n < args->ndeps; n++) |
122 | access_dep (i: args->deps[n]); |
123 | } |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | /* This test gaps with shared libraries with dynamic TLS that has no |
129 | dependencies. The DTV gap is set with by trying to load an invalid |
130 | module, the entry should be used on the dlopen. */ |
131 | static void |
132 | do_test_no_depedency (void) |
133 | { |
134 | for (int i = 0; i < NMOD; i++) |
135 | { |
136 | load_mod (i); |
137 | /* Bump the generation of mod[0] without using new dtv slot. */ |
138 | unload_mod (i: 0); |
139 | load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135. */ |
140 | load_mod (i: 0); |
141 | /* Access TLS in all loaded modules. */ |
142 | pthread_t t = xpthread_create (attr: 0, thread_func: start, closure: 0); |
143 | xpthread_join (thr: t); |
144 | } |
145 | for (int i = 0; i < NMOD; i++) |
146 | unload_mod (i); |
147 | } |
148 | |
149 | /* The following test check DTV gaps handling with shared libraries that has |
150 | dependencies. It defines 5 different sets: |
151 | |
152 | 1. Single dependency: |
153 | mod0 -> mod1 |
154 | 2. Double dependency: |
155 | mod2 -> [mod3,mod4] |
156 | 3. Double dependency with each dependency depent of another module: |
157 | mod5 -> [mod6,mod7] -> mod8 |
158 | 4. Long chain with one double dependency in the middle: |
159 | mod9 -> [mod10, mod11] -> mod12 -> mod13 |
160 | 5. Long chain with two double depedencies in the middle: |
161 | mod14 -> mod15 -> [mod16, mod17] |
162 | mod15 -> [mod18, mod19] |
163 | |
164 | This does not cover all the possible gaps and configuration, but it |
165 | should check if different dynamic shared sets are placed correctly in |
166 | different gaps configurations. */ |
167 | |
168 | static int |
169 | nmodules (uint32_t v) |
170 | { |
171 | unsigned int r = 0; |
172 | while (v >>= 1) |
173 | r++; |
174 | return r + 1; |
175 | } |
176 | |
177 | static inline bool |
178 | is_mod_set (uint32_t g, uint32_t n) |
179 | { |
180 | return (1U << (n - 1)) & g; |
181 | } |
182 | |
183 | static void |
184 | print_gap (uint32_t g) |
185 | { |
186 | if (!test_verbose) |
187 | return; |
188 | printf (format: "gap: " ); |
189 | int nmods = nmodules (v: g); |
190 | for (int n = 1; n <= nmods; n++) |
191 | printf (format: "%c" , ((1 << (n - 1)) & g) == 0 ? 'G' : 'M'); |
192 | printf (format: "\n" ); |
193 | } |
194 | |
195 | static void |
196 | do_test_dependency (void) |
197 | { |
198 | /* Maps the module and its dependencies, use thread to access the TLS on |
199 | each loaded module. */ |
200 | static const int tlsmanydeps0[] = { 1 }; |
201 | static const int tlsmanydeps1[] = { 3, 4 }; |
202 | static const int tlsmanydeps2[] = { 6, 7, 8 }; |
203 | static const int tlsmanydeps3[] = { 10, 11, 12 }; |
204 | static const int tlsmanydeps4[] = { 15, 16, 17, 18, 19 }; |
205 | static const struct tlsmanydeps_t |
206 | { |
207 | int modi; |
208 | int ndeps; |
209 | const int *deps; |
210 | } tlsmanydeps[] = |
211 | { |
212 | { 0, array_length (tlsmanydeps0), tlsmanydeps0 }, |
213 | { 2, array_length (tlsmanydeps1), tlsmanydeps1 }, |
214 | { 5, array_length (tlsmanydeps2), tlsmanydeps2 }, |
215 | { 9, array_length (tlsmanydeps3), tlsmanydeps3 }, |
216 | { 14, array_length (tlsmanydeps4), tlsmanydeps4 }, |
217 | }; |
218 | |
219 | /* The gap configuration is defined as a bitmap: the bit set represents a |
220 | loaded module prior the tests execution, while a bit unsed is a module |
221 | unloaded. Not all permtation will show gaps, but it is simpler than |
222 | define each one independently. */ |
223 | for (uint32_t g = 0; g < 64; g++) |
224 | { |
225 | print_gap (g); |
226 | int nmods = nmodules (v: g); |
227 | |
228 | int mods[nmods]; |
229 | /* We use '0' as indication for a gap, to avoid the dlclose on iteration |
230 | cleanup. */ |
231 | for (int n = 1; n < nmods; n++) |
232 | { |
233 | load_mod (i: n); |
234 | mods[n] = n; |
235 | } |
236 | for (int n = 1; n < nmods; n++) |
237 | { |
238 | if (!is_mod_set (g, n)) |
239 | { |
240 | unload_mod (i: n); |
241 | mods[n] = 0; |
242 | } |
243 | } |
244 | |
245 | for (int t = 0; t < array_length (tlsmanydeps); t++) |
246 | { |
247 | char *moddepname = xasprintf (format: "tst-tls-manydynamic%dmod-dep.so" , |
248 | tlsmanydeps[t].modi); |
249 | void *moddep = xdlopen (filename: moddepname, RTLD_LAZY); |
250 | |
251 | /* Access TLS in all loaded modules. */ |
252 | struct start_args args = |
253 | { |
254 | moddepname, |
255 | moddep, |
256 | tlsmanydeps[t].modi, |
257 | tlsmanydeps[t].ndeps, |
258 | tlsmanydeps[t].deps |
259 | }; |
260 | pthread_t t = xpthread_create (attr: 0, thread_func: start, closure: &args); |
261 | xpthread_join (thr: t); |
262 | |
263 | free (ptr: moddepname); |
264 | xdlclose (handle: moddep); |
265 | } |
266 | |
267 | for (int n = 1; n <= nmods; n++) |
268 | if (mods[n] != 0) |
269 | unload_mod (i: n); |
270 | } |
271 | } |
272 | |
273 | /* The following test check DTV gaps handling with shared libraries that has |
274 | invalid dependencies. It defines 5 different sets: |
275 | |
276 | 1. Single dependency: |
277 | mod0 -> invalid |
278 | 2. Double dependency: |
279 | mod1 -> [mod2,invalid] |
280 | 3. Double dependency with each dependency depent of another module: |
281 | mod3 -> [mod4,mod5] -> invalid |
282 | 4. Long chain with one double dependency in the middle: |
283 | mod6 -> [mod7, mod8] -> mod12 -> invalid |
284 | 5. Long chain with two double depedencies in the middle: |
285 | mod10 -> mod11 -> [mod12, mod13] |
286 | mod12 -> [mod14, invalid] |
287 | |
288 | This does not cover all the possible gaps and configuration, but it |
289 | should check if different dynamic shared sets are placed correctly in |
290 | different gaps configurations. */ |
291 | |
292 | static void |
293 | do_test_invalid_dependency (bool bind_now) |
294 | { |
295 | static const int tlsmanydeps[] = { 0, 1, 3, 6, 10 }; |
296 | |
297 | /* The gap configuration is defined as a bitmap: the bit set represents a |
298 | loaded module prior the tests execution, while a bit unsed is a module |
299 | unloaded. Not all permtation will show gaps, but it is simpler than |
300 | define each one independently. */ |
301 | for (uint32_t g = 0; g < 64; g++) |
302 | { |
303 | print_gap (g); |
304 | int nmods = nmodules (v: g); |
305 | |
306 | int mods[nmods]; |
307 | /* We use '0' as indication for a gap, to avoid the dlclose on iteration |
308 | cleanup. */ |
309 | for (int n = 1; n < nmods; n++) |
310 | { |
311 | load_mod (i: n); |
312 | mods[n] = n; |
313 | } |
314 | for (int n = 1; n < nmods; n++) |
315 | { |
316 | if (!is_mod_set (g, n)) |
317 | { |
318 | unload_mod (i: n); |
319 | mods[n] = 0; |
320 | } |
321 | } |
322 | |
323 | for (int t = 0; t < array_length (tlsmanydeps); t++) |
324 | { |
325 | char *moddepname = xasprintf (format: "tst-tls-manydynamic%dmod-dep-bad.so" , |
326 | tlsmanydeps[t]); |
327 | void *moddep; |
328 | if (bind_now) |
329 | { |
330 | moddep = dlopen (file: moddepname, RTLD_NOW); |
331 | TEST_VERIFY (moddep == 0); |
332 | } |
333 | else |
334 | moddep = dlopen (file: moddepname, RTLD_LAZY); |
335 | |
336 | /* Access TLS in all loaded modules. */ |
337 | pthread_t t = xpthread_create (attr: 0, thread_func: start, NULL); |
338 | xpthread_join (thr: t); |
339 | |
340 | free (ptr: moddepname); |
341 | if (!bind_now) |
342 | xdlclose (handle: moddep); |
343 | } |
344 | |
345 | for (int n = 1; n <= nmods; n++) |
346 | if (mods[n] != 0) |
347 | unload_mod (i: n); |
348 | } |
349 | } |
350 | |
351 | static int |
352 | do_test (void) |
353 | { |
354 | do_test_no_depedency (); |
355 | do_test_dependency (); |
356 | do_test_invalid_dependency (true); |
357 | do_test_invalid_dependency (false); |
358 | |
359 | return 0; |
360 | } |
361 | |
362 | #include <support/test-driver.c> |
363 | |