rtld: properly handle root directory in load path (bug 30435)
[platform/upstream/glibc.git] / elf / tst-tls20.c
1 /* Test dtv setup if entries don't have monotone increasing generation.
2    Copyright (C) 2021-2023 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
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);
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
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
109 static void *
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
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
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.  */
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
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
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>