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
load_fail(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
load_mod(int i)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
unload_mod(int i)53 unload_mod (int i)
54 {
55   if (mod[i] != NULL)
56     xdlclose (mod[i]);
57   mod[i] = NULL;
58 }
59 
60 static void
access(int i)61 access (int i)
62 {
63   char *buf = xasprintf ("tls_global_%02d", i);
64   dlerror ();
65   int *p = dlsym (mod[i], buf);
66   if (test_verbose)
67     printf ("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 (buf);
73 }
74 
75 static void
access_mod(const char * modname,void * mod,int i)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
access_dep(int i)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 
109 static void *
start(void * a)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 (args->modname, args->mod, args->modi);
121       for (int n = 0; n < args->ndeps; n++)
122 	access_dep (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
do_test_no_depedency(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 (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     }
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
nmodules(uint32_t v)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
is_mod_set(uint32_t g,uint32_t n)178 is_mod_set (uint32_t g, uint32_t n)
179 {
180   return (1U << (n - 1)) & g;
181 }
182 
183 static void
print_gap(uint32_t g)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
do_test_dependency(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.  */
231       for (int n = 1; n < nmods; n++)
232 	{
233 	  load_mod (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 (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
do_test_invalid_dependency(bool bind_now)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.  */
309       for (int n = 1; n < nmods; n++)
310 	{
311 	  load_mod (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 (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
do_test(void)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