]>
Commit | Line | Data |
---|---|---|
8f85075a | 1 | /* Test dtv setup if entries don't have monotone increasing generation. |
581c785b | 2 | Copyright (C) 2021-2022 Free Software Foundation, Inc. |
8f85075a SN |
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 | ||
ba33937b | 19 | #include <array_length.h> |
8f85075a SN |
20 | #include <dlfcn.h> |
21 | #include <pthread.h> | |
df4cb228 | 22 | #include <stdbool.h> |
3c7c5117 | 23 | #include <stdint.h> |
8f85075a SN |
24 | #include <stdio.h> |
25 | #include <stdlib.h> | |
26 | #include <support/check.h> | |
52290d8c | 27 | #include <support/support.h> |
ba33937b | 28 | #include <support/test-driver.h> |
8f85075a SN |
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 ("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 ("tst-tls-manydynamic%02dmod.so", i); | |
48 | mod[i] = xdlopen (buf, RTLD_LAZY); | |
49 | free (buf); | |
50 | } | |
51 | ||
52 | static void | |
53 | unload_mod (int i) | |
54 | { | |
55 | if (mod[i] != NULL) | |
56 | xdlclose (mod[i]); | |
57 | mod[i] = NULL; | |
58 | } | |
59 | ||
60 | static void | |
61 | access (int i) | |
62 | { | |
63 | char *buf = xasprintf ("tls_global_%02d", i); | |
64 | dlerror (); | |
65 | int *p = dlsym (mod[i], buf); | |
ba33937b AZ |
66 | if (test_verbose) |
67 | printf ("mod[%d]: &tls = %p\n", i, p); | |
8f85075a SN |
68 | if (p == NULL) |
69 | FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ()); | |
ba33937b | 70 | TEST_COMPARE (*p, 0); |
8f85075a SN |
71 | ++*p; |
72 | free (buf); | |
73 | } | |
74 | ||
ba33937b AZ |
75 | static void |
76 | access_mod (const char *modname, void *mod, int i) | |
77 | { | |
78 | char *modsym = xasprintf ("tls_global_%d", i); | |
79 | dlerror (); | |
80 | int *p = dlsym (mod, modsym); | |
81 | if (test_verbose) | |
82 | printf ("%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 (modsym); | |
88 | } | |
89 | ||
90 | static void | |
91 | access_dep (int i) | |
92 | { | |
93 | char *modname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", i); | |
94 | void *moddep = xdlopen (modname, RTLD_LAZY); | |
95 | access_mod (modname, moddep, i); | |
96 | free (modname); | |
97 | xdlclose (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 | ||
8f85075a SN |
109 | static void * |
110 | start (void *a) | |
111 | { | |
ba33937b AZ |
112 | struct start_args *args = a; |
113 | ||
8f85075a SN |
114 | for (int i = 0; i < NMOD; i++) |
115 | if (mod[i] != NULL) | |
116 | access (i); | |
ba33937b AZ |
117 | |
118 | if (args != NULL) | |
119 | { | |
120 | access_mod (args->modname, args->mod, args->modi); | |
121 | for (int n = 0; n < args->ndeps; n++) | |
122 | access_dep (args->deps[n]); | |
123 | } | |
124 | ||
8f85075a SN |
125 | return 0; |
126 | } | |
127 | ||
ba33937b AZ |
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) | |
8f85075a | 133 | { |
ba33937b | 134 | for (int i = 0; i < NMOD; i++) |
8f85075a SN |
135 | { |
136 | load_mod (i); | |
137 | /* Bump the generation of mod[0] without using new dtv slot. */ | |
138 | unload_mod (0); | |
139 | load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135. */ | |
140 | load_mod (0); | |
141 | /* Access TLS in all loaded modules. */ | |
142 | pthread_t t = xpthread_create (0, start, 0); | |
143 | xpthread_join (t); | |
144 | } | |
ba33937b | 145 | for (int i = 0; i < NMOD; i++) |
8f85075a | 146 | unload_mod (i); |
ba33937b AZ |
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 ("gap: "); | |
189 | int nmods = nmodules (g); | |
190 | for (int n = 1; n <= nmods; n++) | |
191 | printf ("%c", ((1 << (n - 1)) & g) == 0 ? 'G' : 'M'); | |
192 | printf ("\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 (g); | |
227 | ||
228 | int mods[nmods]; | |
229 | /* We use '0' as indication for a gap, to avoid the dlclose on iteration | |
230 | cleanup. */ | |
881b68e4 | 231 | for (int n = 1; n < nmods; n++) |
ba33937b AZ |
232 | { |
233 | load_mod (n); | |
234 | mods[n] = n; | |
235 | } | |
881b68e4 | 236 | for (int n = 1; n < nmods; n++) |
ba33937b AZ |
237 | { |
238 | if (!is_mod_set (g, n)) | |
239 | { | |
240 | unload_mod (n); | |
241 | mods[n] = 0; | |
242 | } | |
243 | } | |
244 | ||
245 | for (int t = 0; t < array_length (tlsmanydeps); t++) | |
246 | { | |
247 | char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", | |
248 | tlsmanydeps[t].modi); | |
249 | void *moddep = xdlopen (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 (0, start, &args); | |
261 | xpthread_join (t); | |
262 | ||
263 | free (moddepname); | |
264 | xdlclose (moddep); | |
265 | } | |
266 | ||
267 | for (int n = 1; n <= nmods; n++) | |
268 | if (mods[n] != 0) | |
269 | unload_mod (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 (g); | |
305 | ||
306 | int mods[nmods]; | |
307 | /* We use '0' as indication for a gap, to avoid the dlclose on iteration | |
308 | cleanup. */ | |
881b68e4 | 309 | for (int n = 1; n < nmods; n++) |
ba33937b AZ |
310 | { |
311 | load_mod (n); | |
312 | mods[n] = n; | |
313 | } | |
881b68e4 | 314 | for (int n = 1; n < nmods; n++) |
ba33937b AZ |
315 | { |
316 | if (!is_mod_set (g, n)) | |
317 | { | |
318 | unload_mod (n); | |
319 | mods[n] = 0; | |
320 | } | |
321 | } | |
322 | ||
323 | for (int t = 0; t < array_length (tlsmanydeps); t++) | |
324 | { | |
325 | char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep-bad.so", | |
326 | tlsmanydeps[t]); | |
327 | void *moddep; | |
328 | if (bind_now) | |
329 | { | |
330 | moddep = dlopen (moddepname, RTLD_NOW); | |
331 | TEST_VERIFY (moddep == 0); | |
332 | } | |
333 | else | |
334 | moddep = dlopen (moddepname, RTLD_LAZY); | |
335 | ||
336 | /* Access TLS in all loaded modules. */ | |
337 | pthread_t t = xpthread_create (0, start, NULL); | |
338 | xpthread_join (t); | |
339 | ||
340 | free (moddepname); | |
341 | if (!bind_now) | |
342 | xdlclose (moddep); | |
343 | } | |
344 | ||
345 | for (int n = 1; n <= nmods; n++) | |
346 | if (mods[n] != 0) | |
347 | unload_mod (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 | ||
8f85075a SN |
359 | return 0; |
360 | } | |
361 | ||
362 | #include <support/test-driver.c> |