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