1 /* _dl_find_object test with parallelism.
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    <https://www.gnu.org/licenses/>.  */
18 
19 #include <array_length.h>
20 #include <dlfcn.h>
21 #include <elf/dl-find_object.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <support/check.h>
25 #include <support/support.h>
26 #include <support/xdlfcn.h>
27 #include <support/xthread.h>
28 #include <support/xunistd.h>
29 
30 /* Computes the expected _dl_find_object result directly from the
31    map.  */
32 static void
from_map(struct link_map * l,struct dl_find_object * expected)33 from_map (struct link_map *l, struct dl_find_object *expected)
34 {
35   struct dl_find_object_internal internal;
36   _dl_find_object_from_map (l, &internal);
37   _dl_find_object_to_external (&internal, expected);
38 }
39 
40 /* Returns the soname for the test object NUMBER.  */
41 static char *
soname(int number)42 soname (int number)
43 {
44   return xasprintf ("tst-dl_find_object-mod%d.so", number);
45 }
46 
47 /* Returns the data symbol name for the test object NUMBER.  */
48 static char *
symbol(int number)49 symbol (int number)
50 {
51   return xasprintf ("mod%d_data", number);
52 }
53 
54 struct verify_data
55 {
56   char *soname;
57   void *address;                /* Address in the shared object.  */
58   struct dl_find_object dlfo;
59   pthread_t thr;
60 };
61 
62 /* Compare _dl_find_object result at ADDRESS with *EXPECTED.  */
63 static void
check(void * address,struct dl_find_object * expected,int line)64 check (void *address, struct dl_find_object *expected, int line)
65 {
66   struct dl_find_object actual;
67   int ret = _dl_find_object (address, &actual);
68   if (expected == NULL)
69     {
70       if (ret != -1)
71         {
72           support_record_failure ();
73           printf ("%s:%d: unexpected success for %p\n",
74                   __FILE__, line, address);
75         }
76       return;
77     }
78   if (ret != 0)
79     {
80       support_record_failure ();
81       printf ("%s:%d: unexpected failure for %p\n",
82               __FILE__, line, address);
83       return;
84     }
85 
86   if (actual.dlfo_flags != expected->dlfo_flags)
87     {
88       support_record_failure ();
89       printf ("%s:%d: error: %p: flags is %llu, expected %llu\n",
90               __FILE__, line, address,
91               actual.dlfo_flags, expected->dlfo_flags);
92     }
93   if (actual.dlfo_flags != expected->dlfo_flags)
94     {
95       support_record_failure ();
96       printf ("%s:%d: error: %p: map start is %p, expected %p\n",
97               __FILE__, line,
98               address, actual.dlfo_map_start, expected->dlfo_map_start);
99     }
100   if (actual.dlfo_map_end != expected->dlfo_map_end)
101     {
102       support_record_failure ();
103       printf ("%s:%d: error: %p: map end is %p, expected %p\n",
104               __FILE__, line,
105               address, actual.dlfo_map_end, expected->dlfo_map_end);
106     }
107   if (actual.dlfo_link_map != expected->dlfo_link_map)
108     {
109       support_record_failure ();
110       printf ("%s:%d: error: %p: link map is %p, expected %p\n",
111               __FILE__, line,
112               address, actual.dlfo_link_map, expected->dlfo_link_map);
113     }
114   if (actual.dlfo_eh_frame != expected->dlfo_eh_frame)
115     {
116       support_record_failure ();
117       printf ("%s:%d: error: %p: EH frame is %p, expected %p\n",
118               __FILE__, line,
119               address, actual.dlfo_eh_frame, expected->dlfo_eh_frame);
120     }
121 #if DLFO_STRUCT_HAS_EH_DBASE
122   if (actual.dlfo_eh_dbase != expected->dlfo_eh_dbase)
123     {
124       support_record_failure ();
125       printf ("%s:%d: error: %p: data base is %p, expected %p\n",
126               __FILE__, line,
127               address, actual.dlfo_eh_dbase, expected->dlfo_eh_dbase);
128     }
129 #endif
130 #if DLFO_STRUCT_HAS_EH_COUNT
131   if (actual.dlfo_eh_count != expected->dlfo_eh_count)
132     {
133       support_record_failure ();
134       printf ("%s:%d: error: %p: count is %d, expected %d\n",
135               __FILE__, line,
136               address, actual.dlfo_eh_count, expected->dlfo_eh_count);
137     }
138 #endif
139 }
140 
141 /* Request process termination after 0.3 seconds.  */
142 static bool exit_requested;
143 static void *
exit_thread(void * ignored)144 exit_thread (void *ignored)
145 {
146   usleep (300 * 1000);
147   __atomic_store_n (&exit_requested, true,  __ATOMIC_RELAXED);
148   return NULL;
149 }
150 
151 static void *
verify_thread(void * closure)152 verify_thread (void *closure)
153 {
154   struct verify_data *data = closure;
155 
156   while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
157     {
158       check (data->address, &data->dlfo, __LINE__);
159       check (data->dlfo.dlfo_map_start, &data->dlfo, __LINE__);
160       check (data->dlfo.dlfo_map_end - 1, &data->dlfo, __LINE__);
161     }
162 
163   return NULL;
164 }
165 
166 /* Sets up the verification data, dlopen'ing shared object NUMBER, and
167    launches a verification thread.  */
168 static void
start_verify(int number,struct verify_data * data)169 start_verify (int number, struct verify_data *data)
170 {
171   data->soname = soname (number);
172   struct link_map *l = xdlopen (data->soname, RTLD_NOW);
173   from_map (l, &data->dlfo);
174   TEST_VERIFY_EXIT (data->dlfo.dlfo_link_map == l);
175   char *sym = symbol (number);
176   data->address = xdlsym (data->dlfo.dlfo_link_map, sym);
177   free (sym);
178   data->thr = xpthread_create (NULL, verify_thread, data);
179 }
180 
181 
182 static int
do_test(void)183 do_test (void)
184 {
185   struct verify_data data_mod2;
186   struct verify_data data_mod4;
187   struct verify_data data_mod7;
188 
189   /* Load the modules with gaps.  */
190   {
191     void *mod1 = xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW);
192     start_verify (2, &data_mod2);
193     void *mod3 = xdlopen ("tst-dl_find_object-mod3.so", RTLD_NOW);
194     start_verify (4, &data_mod4);
195     void *mod5 = xdlopen ("tst-dl_find_object-mod5.so", RTLD_NOW);
196     void *mod6 = xdlopen ("tst-dl_find_object-mod6.so", RTLD_NOW);
197     start_verify (7, &data_mod7);
198     xdlclose (mod6);
199     xdlclose (mod5);
200     xdlclose (mod3);
201     xdlclose (mod1);
202   }
203 
204   /* Objects that continuously opened and closed.  */
205   struct temp_object
206   {
207     char *soname;
208     char *symbol;
209     struct link_map *link_map;
210     void *address;
211   } temp_objects[] =
212     {
213       { soname (1), symbol (1), },
214       { soname (3), symbol (3), },
215       { soname (5), symbol (5), },
216       { soname (6), symbol (6), },
217       { soname (8), symbol (8), },
218       { soname (9), symbol (9), },
219     };
220 
221   pthread_t exit_thr = xpthread_create (NULL, exit_thread, NULL);
222 
223   struct drand48_data state;
224   srand48_r (1, &state);
225   while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
226     {
227       long int idx;
228       lrand48_r (&state, &idx);
229       idx %= array_length (temp_objects);
230       if (temp_objects[idx].link_map == NULL)
231         {
232           temp_objects[idx].link_map = xdlopen (temp_objects[idx].soname,
233                                                 RTLD_NOW);
234           temp_objects[idx].address = xdlsym (temp_objects[idx].link_map,
235                                               temp_objects[idx].symbol);
236         }
237       else
238         {
239           xdlclose (temp_objects[idx].link_map);
240           temp_objects[idx].link_map = NULL;
241           struct dl_find_object dlfo;
242           int ret = _dl_find_object (temp_objects[idx].address, &dlfo);
243           if (ret != -1)
244             {
245               TEST_VERIFY_EXIT (ret == 0);
246               support_record_failure ();
247               printf ("%s: error: %s EH found after dlclose, link map %p\n",
248                       __FILE__, temp_objects[idx].soname, dlfo.dlfo_link_map);
249             }
250         }
251     }
252 
253   xpthread_join (data_mod2.thr);
254   xpthread_join (data_mod4.thr);
255   xpthread_join (data_mod7.thr);
256   xpthread_join (exit_thr);
257 
258   for (size_t i = 0; i < array_length (temp_objects); ++i)
259     {
260       free (temp_objects[i].soname);
261       free (temp_objects[i].symbol);
262       if (temp_objects[i].link_map != NULL)
263         xdlclose (temp_objects[i].link_map);
264     }
265 
266   free (data_mod2.soname);
267   free (data_mod4.soname);
268   xdlclose (data_mod4.dlfo.dlfo_link_map);
269   free (data_mod7.soname);
270   xdlclose (data_mod7.dlfo.dlfo_link_map);
271 
272   return 0;
273 }
274 
275 #include <support/test-driver.c>
276