]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/tst-tls20.c
elf: Include <stdint.h> in tst-tls20.c
[thirdparty/glibc.git] / elf / tst-tls20.c
CommitLineData
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
32static void *mod[NMOD];
33
34static void
35load_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
43static void
44load_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
51static void
52unload_mod (int i)
53{
54 if (mod[i] != NULL)
55 xdlclose (mod[i]);
56 mod[i] = NULL;
57}
58
59static void
60access (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
74static void
75access_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
89static void
90access_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
99struct start_args
100{
101 const char *modname;
102 void *mod;
103 int modi;
104 int ndeps;
105 const int *deps;
106};
107
8f85075a
SN
108static void *
109start (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. */
130static void
131do_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
167static int
168nmodules (uint32_t v)
169{
170 unsigned int r = 0;
171 while (v >>= 1)
172 r++;
173 return r + 1;
174}
175
176static inline bool
177is_mod_set (uint32_t g, uint32_t n)
178{
179 return (1U << (n - 1)) & g;
180}
181
182static void
183print_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
194static void
195do_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
291static void
292do_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
350static int
351do_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>