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
33static void *mod[NMOD];
34
35static void
36load_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
44static void
45load_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
52static void
53unload_mod (int i)
54{
55 if (mod[i] != NULL)
56 xdlclose (handle: mod[i]);
57 mod[i] = NULL;
58}
59
60static void
61access (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
75static void
76access_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
90static void
91access_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
100struct start_args
101{
102 const char *modname;
103 void *mod;
104 int modi;
105 int ndeps;
106 const int *deps;
107};
108
109static void *
110start (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. */
131static void
132do_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
168static int
169nmodules (uint32_t v)
170{
171 unsigned int r = 0;
172 while (v >>= 1)
173 r++;
174 return r + 1;
175}
176
177static inline bool
178is_mod_set (uint32_t g, uint32_t n)
179{
180 return (1U << (n - 1)) & g;
181}
182
183static void
184print_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
195static void
196do_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
292static void
293do_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
351static int
352do_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

source code of glibc/elf/tst-tls20.c