1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <dlfcn.h>
20 #include <elf.h>
21 #include <limits.h>
22 #include <link.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/cdefs.h>
27 #if __has_include(<sys/auxv.h>)
28 #include <sys/auxv.h>
29 #endif
30 #include <sys/user.h>
31
32 #include <string>
33 #include <thread>
34
35 #include <android-base/file.h>
36 #include <android-base/macros.h>
37 #include <android-base/scopeguard.h>
38
39 #include "gtest_globals.h"
40 #include "gtest_utils.h"
41 #include "dlfcn_symlink_support.h"
42 #include "utils.h"
43
44 #define ASSERT_SUBSTR(needle, haystack) \
45 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
46
47
48 static bool g_called = false;
DlSymTestFunction()49 extern "C" void DlSymTestFunction() {
50 g_called = true;
51 }
52
53 static int g_ctor_function_called = 0;
54 static int g_ctor_argc = 0;
55 static char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF);
56 static char** g_ctor_envp = g_ctor_envp;
57
58 extern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor));
59
ctor_function(int argc,char ** argv,char ** envp)60 extern "C" void ctor_function(int argc, char** argv, char** envp) {
61 g_ctor_function_called = 17;
62 g_ctor_argc = argc;
63 g_ctor_argv = argv;
64 g_ctor_envp = envp;
65 }
66
TEST(dlfcn,ctor_function_call)67 TEST(dlfcn, ctor_function_call) {
68 ASSERT_EQ(17, g_ctor_function_called);
69 ASSERT_TRUE(g_ctor_argc = GetArgc());
70 ASSERT_TRUE(g_ctor_argv = GetArgv());
71 ASSERT_TRUE(g_ctor_envp = GetEnvp());
72 }
73
TEST(dlfcn,dlsym_in_executable)74 TEST(dlfcn, dlsym_in_executable) {
75 dlerror(); // Clear any pending errors.
76 void* self = dlopen(nullptr, RTLD_NOW);
77 ASSERT_TRUE(self != nullptr);
78 ASSERT_TRUE(dlerror() == nullptr);
79
80 void* sym = dlsym(self, "DlSymTestFunction");
81 ASSERT_TRUE(sym != nullptr);
82
83 void (*function)() = reinterpret_cast<void(*)()>(sym);
84
85 g_called = false;
86 function();
87 ASSERT_TRUE(g_called);
88
89 ASSERT_EQ(0, dlclose(self));
90 }
91
TEST(dlfcn,dlsym_from_sofile)92 TEST(dlfcn, dlsym_from_sofile) {
93 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
94 ASSERT_TRUE(handle != nullptr) << dlerror();
95
96 // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
97 void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
98 ASSERT_TRUE(symbol == nullptr);
99 ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
100
101 typedef int* (*fn_t)();
102 fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
103 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
104 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
105
106 int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
107 ASSERT_TRUE(ptr != nullptr) << dlerror();
108 ASSERT_EQ(42, *ptr);
109
110 fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
111 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
112 ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
113
114 ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
115 ASSERT_TRUE(ptr != nullptr) << dlerror();
116 ASSERT_EQ(44, *ptr);
117
118 fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
119 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
120 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
121
122 ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
123 ASSERT_TRUE(ptr != nullptr) << dlerror();
124 ASSERT_EQ(43, *ptr);
125
126 dlclose(handle);
127 }
128
TEST(dlfcn,dlsym_from_sofile_with_preload)129 TEST(dlfcn, dlsym_from_sofile_with_preload) {
130 void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
131 ASSERT_TRUE(preload != nullptr) << dlerror();
132
133 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
134 ASSERT_TRUE(handle != nullptr) << dlerror();
135
136 // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
137 void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
138 ASSERT_TRUE(symbol == nullptr);
139 ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
140
141 typedef int* (*fn_t)();
142 fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
143 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
144 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
145
146 int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
147 ASSERT_TRUE(ptr != nullptr) << dlerror();
148 ASSERT_EQ(42, *ptr);
149
150 fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
151 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
152 ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
153
154 ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
155 ASSERT_TRUE(ptr != nullptr) << dlerror();
156 ASSERT_EQ(44, *ptr);
157
158 fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
159 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
160 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
161
162 ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
163 ASSERT_TRUE(ptr != nullptr) << dlerror();
164 ASSERT_EQ(43, *ptr);
165
166 dlclose(handle);
167 dlclose(preload);
168 }
169
TEST(dlfcn,dlsym_handle_global_sym)170 TEST(dlfcn, dlsym_handle_global_sym) {
171 // check that we do not look into global group
172 // when looking up symbol by handle
173 void* handle = dlopen("libtest_empty.so", RTLD_NOW);
174 dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
175 void* sym = dlsym(handle, "getRandomNumber");
176 ASSERT_TRUE(sym == nullptr);
177 ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
178
179 sym = dlsym(handle, "DlSymTestFunction");
180 ASSERT_TRUE(sym == nullptr);
181 ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
182 dlclose(handle);
183 }
184
TEST(dlfcn,dlsym_handle_empty_symbol)185 TEST(dlfcn, dlsym_handle_empty_symbol) {
186 // check that dlsym of an empty symbol fails (see http://b/33530622)
187 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW);
188 ASSERT_TRUE(handle != nullptr) << dlerror();
189 void* sym = dlsym(handle, "");
190 ASSERT_TRUE(sym == nullptr);
191 ASSERT_SUBSTR("undefined symbol: ", dlerror());
192 dlclose(handle);
193 }
194
TEST(dlfcn,dlsym_with_dependencies)195 TEST(dlfcn, dlsym_with_dependencies) {
196 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
197 ASSERT_TRUE(handle != nullptr);
198 dlerror();
199 // This symbol is in DT_NEEDED library.
200 void* sym = dlsym(handle, "getRandomNumber");
201 ASSERT_TRUE(sym != nullptr) << dlerror();
202 int (*fn)(void);
203 fn = reinterpret_cast<int (*)(void)>(sym);
204 EXPECT_EQ(4, fn());
205 dlclose(handle);
206 }
207
TEST(dlfcn,dlopen_noload)208 TEST(dlfcn, dlopen_noload) {
209 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
210 ASSERT_TRUE(handle == nullptr);
211 handle = dlopen("libtest_simple.so", RTLD_NOW);
212 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
213 ASSERT_TRUE(handle != nullptr);
214 ASSERT_TRUE(handle2 != nullptr);
215 ASSERT_TRUE(handle == handle2);
216 ASSERT_EQ(0, dlclose(handle));
217 ASSERT_EQ(0, dlclose(handle2));
218 }
219
TEST(dlfcn,dlopen_by_soname)220 TEST(dlfcn, dlopen_by_soname) {
221 static const char* soname = "libdlext_test_soname.so";
222 static const char* filename = "libdlext_test_different_soname.so";
223 // 1. Make sure there is no library with soname in default search path
224 void* handle = dlopen(soname, RTLD_NOW);
225 ASSERT_TRUE(handle == nullptr);
226
227 // 2. Load a library using filename
228 handle = dlopen(filename, RTLD_NOW);
229 ASSERT_TRUE(handle != nullptr) << dlerror();
230
231 // 3. Find library by soname
232 void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
233 ASSERT_TRUE(handle_soname != nullptr) << dlerror();
234 ASSERT_EQ(handle, handle_soname);
235
236 // 4. RTLD_NOLOAD should still work with filename
237 void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
238 ASSERT_TRUE(handle_filename != nullptr) << dlerror();
239 ASSERT_EQ(handle, handle_filename);
240
241 dlclose(handle_filename);
242 dlclose(handle_soname);
243 dlclose(handle);
244 }
245
TEST(dlfcn,dlopen_vdso)246 TEST(dlfcn, dlopen_vdso) {
247 #if __has_include(<sys/auxv.h>)
248 if (getauxval(AT_SYSINFO_EHDR) == 0) {
249 GTEST_SKIP() << "getauxval(AT_SYSINFO_EHDR) == 0, skipping this test";
250 }
251 #endif
252
253 const char* vdso_name = "linux-vdso.so.1";
254 #if defined(__i386__)
255 vdso_name = "linux-gate.so.1";
256 #endif
257 void* handle = dlopen(vdso_name, RTLD_NOW);
258 ASSERT_TRUE(handle != nullptr) << dlerror();
259 dlclose(handle);
260 }
261
262 // HWASan uses an ifunc to describe the location of its shadow memory,
263 // so even though it's an unusual case, Android needs to support
264 // "ifunc variables".
TEST(dlfcn,ifunc_variable)265 TEST(dlfcn, ifunc_variable) {
266 typedef const char* (*fn_ptr)();
267
268 // ifunc's choice depends on whether IFUNC_CHOICE has a value
269 // first check the set case
270 setenv("IFUNC_CHOICE", "set", 1);
271 // preload libtest_ifunc_variable_impl.so
272 void* handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
273 void* handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
274 ASSERT_TRUE(handle != nullptr) << dlerror();
275 const char** foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
276 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
277 ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
278 ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
279 ASSERT_EQ(strncmp("set", *foo_ptr, 3), 0);
280 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
281 dlclose(handle);
282 dlclose(handle_impl);
283
284 // then check the unset case
285 unsetenv("IFUNC_CHOICE");
286 handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
287 handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
288 ASSERT_TRUE(handle != nullptr) << dlerror();
289 foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
290 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
291 ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
292 ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
293 ASSERT_EQ(strncmp("unset", *foo_ptr, 5), 0);
294 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
295 dlclose(handle);
296 dlclose(handle_impl);
297 }
298
TEST(dlfcn,ifunc)299 TEST(dlfcn, ifunc) {
300 typedef const char* (*fn_ptr)();
301
302 // ifunc's choice depends on whether IFUNC_CHOICE has a value
303 // first check the set case
304 setenv("IFUNC_CHOICE", "set", 1);
305 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
306 ASSERT_TRUE(handle != nullptr) << dlerror();
307 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
308 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
309 ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
310 ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
311 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
312 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
313 dlclose(handle);
314
315 // then check the unset case
316 unsetenv("IFUNC_CHOICE");
317 handle = dlopen("libtest_ifunc.so", RTLD_NOW);
318 ASSERT_TRUE(handle != nullptr) << dlerror();
319 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
320 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
321 ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
322 ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
323 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
324 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
325 dlclose(handle);
326 }
327
TEST(dlfcn,ifunc_ctor_call)328 TEST(dlfcn, ifunc_ctor_call) {
329 typedef const char* (*fn_ptr)();
330
331 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
332 ASSERT_TRUE(handle != nullptr) << dlerror();
333 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
334 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
335 ASSERT_STREQ("false", is_ctor_called());
336
337 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
338 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
339 ASSERT_STREQ("true", is_ctor_called());
340 dlclose(handle);
341 }
342
TEST(dlfcn,ifunc_ctor_call_rtld_lazy)343 TEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
344 typedef const char* (*fn_ptr)();
345
346 void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
347 ASSERT_TRUE(handle != nullptr) << dlerror();
348 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
349 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
350 ASSERT_STREQ("false", is_ctor_called());
351
352 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
353 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
354 ASSERT_STREQ("true", is_ctor_called());
355 dlclose(handle);
356 }
357
TEST(dlfcn,dlopen_check_relocation_dt_needed_order)358 TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
359 // This is the structure of the test library and
360 // its dt_needed libraries
361 // libtest_relo_check_dt_needed_order.so
362 // |
363 // +-> libtest_relo_check_dt_needed_order_1.so
364 // |
365 // +-> libtest_relo_check_dt_needed_order_2.so
366 //
367 // The root library references relo_test_get_answer_lib - which is defined
368 // in both dt_needed libraries, the correct relocation should
369 // use the function defined in libtest_relo_check_dt_needed_order_1.so
370 void* handle = nullptr;
371 auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
372
373 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
374 ASSERT_TRUE(handle != nullptr) << dlerror();
375
376 typedef int (*fn_t) (void);
377 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
378 ASSERT_TRUE(fn != nullptr) << dlerror();
379 ASSERT_EQ(1, fn());
380 }
381
TEST(dlfcn,dlopen_check_order_dlsym)382 TEST(dlfcn, dlopen_check_order_dlsym) {
383 // Here is how the test library and its dt_needed
384 // libraries are arranged
385 //
386 // libtest_check_order_children.so
387 // |
388 // +-> ..._1_left.so
389 // | |
390 // | +-> ..._a.so
391 // | |
392 // | +-> ...r_b.so
393 // |
394 // +-> ..._2_right.so
395 // | |
396 // | +-> ..._d.so
397 // | |
398 // | +-> ..._b.so
399 // |
400 // +-> ..._3_c.so
401 //
402 // load order should be (1, 2, 3, a, b, d)
403 //
404 // get_answer() is defined in (2, 3, a, b, c)
405 // get_answer2() is defined in (b, d)
406 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
407 ASSERT_TRUE(sym == nullptr);
408 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
409 ASSERT_TRUE(handle != nullptr) << dlerror();
410 typedef int (*fn_t) (void);
411 fn_t fn, fn2;
412 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
413 ASSERT_TRUE(fn != nullptr) << dlerror();
414 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
415 ASSERT_TRUE(fn2 != nullptr) << dlerror();
416
417 ASSERT_EQ(42, fn());
418 ASSERT_EQ(43, fn2());
419 dlclose(handle);
420 }
421
TEST(dlfcn,dlopen_check_order_reloc_siblings)422 TEST(dlfcn, dlopen_check_order_reloc_siblings) {
423 // This is how this one works:
424 // we lookup and call get_answer which is defined in '_2.so'
425 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
426 // the correct _impl() is implemented by '_a.so';
427 //
428 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
429 //
430 // Here is the picture:
431 //
432 // libtest_check_order_reloc_siblings.so
433 // |
434 // +-> ..._1.so <- empty
435 // | |
436 // | +-> ..._a.so <- exports correct answer_impl()
437 // | |
438 // | +-> ..._b.so <- every other letter exporting incorrect one.
439 // |
440 // +-> ..._2.so <- empty
441 // | |
442 // | +-> ..._c.so
443 // | |
444 // | +-> ..._d.so
445 // |
446 // +-> ..._3.so <- empty
447 // |
448 // +-> ..._e.so
449 // |
450 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
451 // implements incorrect get_answer_impl()
452
453 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
454 ASSERT_TRUE(handle == nullptr);
455 #ifdef __BIONIC__
456 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
457 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
458 #endif
459
460 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
461 ASSERT_TRUE(handle != nullptr) << dlerror();
462
463 typedef int (*fn_t) (void);
464 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
465 ASSERT_TRUE(fn != nullptr) << dlerror();
466 ASSERT_EQ(42, fn());
467
468 ASSERT_EQ(0, dlclose(handle));
469 }
470
TEST(dlfcn,dlopen_check_order_reloc_siblings_with_preload)471 TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
472 // This test uses the same library as dlopen_check_order_reloc_siblings.
473 // Unlike dlopen_check_order_reloc_siblings it preloads
474 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
475 // dlopen(libtest_check_order_reloc_siblings.so)
476
477 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
478 ASSERT_TRUE(handle == nullptr);
479 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
480 ASSERT_TRUE(handle == nullptr);
481
482 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
483 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
484
485 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
486 ASSERT_TRUE(handle != nullptr) << dlerror();
487
488 ASSERT_EQ(0, dlclose(handle_for_1));
489
490 typedef int (*fn_t) (void);
491 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
492 ASSERT_TRUE(fn != nullptr) << dlerror();
493 ASSERT_EQ(42, fn());
494
495 ASSERT_EQ(0, dlclose(handle));
496 }
497
TEST(dlfcn,dlopen_check_order_reloc_grandchild)498 TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
499 // This is how this one works:
500 // we lookup and call grandchild_get_answer which is defined in '_2.so'
501 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
502 // the correct _impl() is implemented by '_c_1.so';
503 //
504 // Here is the picture of subtree:
505 //
506 // libtest_check_order_reloc_siblings.so
507 // |
508 // +-> ..._2.so <- grandchild_get_answer()
509 // |
510 // +-> ..._c.so <- empty
511 // | |
512 // | +-> _c_1.so <- exports correct answer_impl()
513 // | |
514 // | +-> _c_2.so <- exports incorrect answer_impl()
515 // |
516 // +-> ..._d.so <- empty
517
518 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
519 ASSERT_TRUE(handle == nullptr);
520 #ifdef __BIONIC__
521 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
522 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
523 #endif
524
525 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
526 ASSERT_TRUE(handle != nullptr) << dlerror();
527
528 typedef int (*fn_t) (void);
529 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
530 ASSERT_TRUE(fn != nullptr) << dlerror();
531 ASSERT_EQ(42, fn());
532
533 ASSERT_EQ(0, dlclose(handle));
534 }
535
TEST(dlfcn,dlopen_check_order_reloc_nephew)536 TEST(dlfcn, dlopen_check_order_reloc_nephew) {
537 // This is how this one works:
538 // we lookup and call nephew_get_answer which is defined in '_2.so'
539 // and in turn calls external get_answer_impl() defined in '_[a-f].so'
540 // the correct _impl() is implemented by '_a.so';
541 //
542 // Here is the picture:
543 //
544 // libtest_check_order_reloc_siblings.so
545 // |
546 // +-> ..._1.so <- empty
547 // | |
548 // | +-> ..._a.so <- exports correct answer_impl()
549 // | |
550 // | +-> ..._b.so <- every other letter exporting incorrect one.
551 // |
552 // +-> ..._2.so <- empty
553 // | |
554 // | +-> ..._c.so
555 // | |
556 // | +-> ..._d.so
557 // |
558 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
559 // |
560 // +-> ..._e.so
561 // |
562 // +-> ..._f.so
563
564 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
565 ASSERT_TRUE(handle == nullptr);
566 #ifdef __BIONIC__
567 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
568 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
569 #endif
570
571 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
572 ASSERT_TRUE(handle != nullptr) << dlerror();
573
574 typedef int (*fn_t) (void);
575 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
576 ASSERT_TRUE(fn != nullptr) << dlerror();
577 ASSERT_EQ(42, fn());
578
579 ASSERT_EQ(0, dlclose(handle));
580 }
581
TEST(dlfcn,check_unload_after_reloc)582 TEST(dlfcn, check_unload_after_reloc) {
583 // This is how this one works:
584 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
585 // |
586 // +-> libtest_two_parents_child
587 //
588 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
589 // |
590 // +-> libtest_two_parents_child
591 //
592 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
593 // as a second step it dlopens parent2 and dlcloses parent1...
594
595 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
596 ASSERT_TRUE(handle != nullptr) << dlerror();
597
598 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
599 ASSERT_TRUE(handle2 != nullptr) << dlerror();
600
601 typedef int (*fn_t) (void);
602 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
603 ASSERT_TRUE(fn != nullptr) << dlerror();
604 ASSERT_EQ(42, fn());
605
606 ASSERT_EQ(0, dlclose(handle));
607
608 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
609 ASSERT_TRUE(handle != nullptr);
610 ASSERT_EQ(0, dlclose(handle));
611
612 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
613 ASSERT_TRUE(fn != nullptr) << dlerror();
614 ASSERT_EQ(42, fn());
615
616 ASSERT_EQ(0, dlclose(handle2));
617
618 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
619 ASSERT_TRUE(handle == nullptr);
620 }
621
check_order_reloc_root_get_answer_impl()622 extern "C" int check_order_reloc_root_get_answer_impl() {
623 return 42;
624 }
625
TEST(dlfcn,dlopen_check_order_reloc_main_executable)626 TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
627 // This is how this one works:
628 // we lookup and call get_answer3 which is defined in 'root.so'
629 // and in turn calls external root_get_answer_impl() defined in _2.so and
630 // above the correct _impl() is one in the executable.
631 //
632 // libtest_check_order_reloc_root.so
633 // |
634 // +-> ..._1.so <- empty
635 // |
636 // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
637 //
638
639 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
640 ASSERT_TRUE(handle == nullptr);
641 #ifdef __BIONIC__
642 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
643 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
644 #endif
645
646 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
647 ASSERT_TRUE(handle != nullptr) << dlerror();
648
649 typedef int (*fn_t) (void);
650 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
651 ASSERT_TRUE(fn != nullptr) << dlerror();
652 ASSERT_EQ(42, fn());
653
654 ASSERT_EQ(0, dlclose(handle));
655 }
656
TEST(dlfcn,dlopen_check_rtld_local)657 TEST(dlfcn, dlopen_check_rtld_local) {
658 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
659 ASSERT_TRUE(sym == nullptr);
660
661 // implicit RTLD_LOCAL
662 void* handle = dlopen("libtest_simple.so", RTLD_NOW);
663 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
664 ASSERT_TRUE(sym == nullptr);
665 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
666 sym = dlsym(handle, "dlopen_testlib_simple_func");
667 ASSERT_TRUE(sym != nullptr);
668 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
669 dlclose(handle);
670
671 // explicit RTLD_LOCAL
672 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
673 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
674 ASSERT_TRUE(sym == nullptr);
675 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
676 sym = dlsym(handle, "dlopen_testlib_simple_func");
677 ASSERT_TRUE(sym != nullptr);
678 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
679 dlclose(handle);
680 }
681
TEST(dlfcn,dlopen_check_rtld_global)682 TEST(dlfcn, dlopen_check_rtld_global) {
683 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
684 ASSERT_TRUE(sym == nullptr);
685
686 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
687 ASSERT_TRUE(handle != nullptr) << dlerror();
688 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
689 ASSERT_TRUE(sym != nullptr) << dlerror();
690 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
691 dlclose(handle);
692
693 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
694 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
695 ASSERT_EQ(sym, sym_after_dlclose);
696
697 // Check if dlsym() for main program's handle searches RTLD_GLOBAL
698 // shared libraries after symbol was not found in the main executable
699 // and dependent libraries.
700 void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
701 sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
702 ASSERT_TRUE(sym != nullptr) << dlerror();
703
704 dlclose(handle_for_main_executable);
705 }
706
707 // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
708 // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
709 // libtest_with_dependency_loop_a.so
TEST(dlfcn,dlopen_check_loop)710 TEST(dlfcn, dlopen_check_loop) {
711 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
712 ASSERT_TRUE(handle != nullptr) << dlerror();
713 void* f = dlsym(handle, "dlopen_test_loopy_function");
714 ASSERT_TRUE(f != nullptr) << dlerror();
715 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
716 ASSERT_EQ(0, dlclose(handle));
717
718 // dlopen second time to make sure that the library was unloaded correctly
719 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
720 ASSERT_TRUE(handle == nullptr);
721 #ifdef __BIONIC__
722 ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
723 #else
724 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
725 ASSERT_TRUE(dlerror() == nullptr);
726 #endif
727
728 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
729 ASSERT_TRUE(handle == nullptr);
730 }
731
TEST(dlfcn,dlopen_nodelete)732 TEST(dlfcn, dlopen_nodelete) {
733 static bool is_unloaded = false;
734
735 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
736 ASSERT_TRUE(handle != nullptr) << dlerror();
737 void (*set_unload_flag_ptr)(bool*);
738 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
739 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
740 set_unload_flag_ptr(&is_unloaded);
741
742 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
743 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
744 ASSERT_EQ(1729U, *taxicab_number);
745 *taxicab_number = 2;
746
747 dlclose(handle);
748 ASSERT_TRUE(!is_unloaded);
749
750 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
751 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
752 ASSERT_EQ(2U, *taxicab_number_after_dlclose);
753
754
755 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
756 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
757 ASSERT_EQ(taxicab_number2, taxicab_number);
758
759 ASSERT_EQ(2U, *taxicab_number2);
760
761 dlclose(handle);
762 ASSERT_TRUE(!is_unloaded);
763 }
764
TEST(dlfcn,dlopen_nodelete_on_second_dlopen)765 TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
766 static bool is_unloaded = false;
767
768 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
769 ASSERT_TRUE(handle != nullptr) << dlerror();
770 void (*set_unload_flag_ptr)(bool*);
771 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
772 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
773 set_unload_flag_ptr(&is_unloaded);
774
775 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
776 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
777
778 ASSERT_EQ(1729U, *taxicab_number);
779 *taxicab_number = 2;
780
781 // This RTLD_NODELETE should be ignored
782 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
783 ASSERT_TRUE(handle1 != nullptr) << dlerror();
784 ASSERT_EQ(handle, handle1);
785
786 dlclose(handle1);
787 dlclose(handle);
788
789 ASSERT_TRUE(is_unloaded);
790 }
791
TEST(dlfcn,dlopen_nodelete_dt_flags_1)792 TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
793 static bool is_unloaded = false;
794
795 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
796 ASSERT_TRUE(handle != nullptr) << dlerror();
797 void (*set_unload_flag_ptr)(bool*);
798 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
799 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
800 set_unload_flag_ptr(&is_unloaded);
801
802 dlclose(handle);
803 ASSERT_TRUE(!is_unloaded);
804 }
805
TEST(dlfcn,dlsym_df_1_global)806 TEST(dlfcn, dlsym_df_1_global) {
807 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
808 ASSERT_TRUE(handle != nullptr) << dlerror();
809 int (*get_answer)();
810 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
811 ASSERT_TRUE(get_answer != nullptr) << dlerror();
812 ASSERT_EQ(42, get_answer());
813 ASSERT_EQ(0, dlclose(handle));
814 }
815
TEST(dlfcn,dlopen_failure)816 TEST(dlfcn, dlopen_failure) {
817 void* self = dlopen("/does/not/exist", RTLD_NOW);
818 ASSERT_TRUE(self == nullptr);
819 #if defined(__BIONIC__)
820 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
821 #else
822 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
823 #endif
824 }
825
TEST(dlfcn,dlclose_unload)826 TEST(dlfcn, dlclose_unload) {
827 const size_t kPageSize = getpagesize();
828
829 void* handle = dlopen("libtest_simple.so", RTLD_NOW);
830 ASSERT_TRUE(handle != nullptr) << dlerror();
831 uint32_t* taxicab_number = static_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
832 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
833 EXPECT_EQ(1729U, *taxicab_number);
834 dlclose(handle);
835 // Making sure that the library has been unmapped as part of library unload
836 // process. Note that mprotect somewhat counter-intuitively returns ENOMEM in
837 // this case.
838 uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(kPageSize - 1);
839 ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), kPageSize, PROT_NONE) != 0);
840 ASSERT_ERRNO(ENOMEM);
841 }
842
ConcurrentDlErrorFn(std::string & error)843 static void ConcurrentDlErrorFn(std::string& error) {
844 ASSERT_TRUE(dlerror() == nullptr);
845
846 void* handle = dlopen("/child/thread", RTLD_NOW);
847 ASSERT_TRUE(handle == nullptr);
848
849 const char* err = dlerror();
850 ASSERT_TRUE(err != nullptr);
851
852 error = err;
853 }
854
TEST(dlfcn,dlerror_concurrent_buffer)855 TEST(dlfcn, dlerror_concurrent_buffer) {
856 void* handle = dlopen("/main/thread", RTLD_NOW);
857 ASSERT_TRUE(handle == nullptr);
858 const char* main_thread_error = dlerror();
859 ASSERT_TRUE(main_thread_error != nullptr);
860 ASSERT_SUBSTR("/main/thread", main_thread_error);
861
862 std::string child_thread_error;
863 std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
864 t.join();
865 ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
866
867 // Check that main thread local buffer was not modified.
868 ASSERT_SUBSTR("/main/thread", main_thread_error);
869 }
870
TEST(dlfcn,dlerror_concurrent)871 TEST(dlfcn, dlerror_concurrent) {
872 void* handle = dlopen("/main/thread", RTLD_NOW);
873 ASSERT_TRUE(handle == nullptr);
874
875 std::string child_thread_error;
876 std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
877 t.join();
878 ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
879
880 const char* main_thread_error = dlerror();
881 ASSERT_TRUE(main_thread_error != nullptr);
882 ASSERT_SUBSTR("/main/thread", main_thread_error);
883 }
884
TEST(dlfcn,dlsym_failures)885 TEST(dlfcn, dlsym_failures) {
886 dlerror(); // Clear any pending errors.
887 void* self = dlopen(nullptr, RTLD_NOW);
888 ASSERT_TRUE(self != nullptr);
889 ASSERT_TRUE(dlerror() == nullptr);
890
891 void* sym;
892
893 #if defined(__BIONIC__) && !defined(__LP64__)
894 #pragma clang diagnostic push
895 #pragma clang diagnostic ignored "-Wnonnull"
896 // RTLD_DEFAULT in lp32 bionic is not (void*)0
897 // so it can be distinguished from the NULL handle.
898 sym = dlsym(nullptr, "test");
899 ASSERT_TRUE(sym == nullptr);
900 ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
901 #pragma clang diagnostic pop
902 #endif
903
904 // Symbol that doesn't exist.
905 sym = dlsym(self, "ThisSymbolDoesNotExist");
906 ASSERT_TRUE(sym == nullptr);
907 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
908
909 ASSERT_EQ(0, dlclose(self));
910 }
911
TEST(dlfcn,dladdr_executable)912 TEST(dlfcn, dladdr_executable) {
913 dlerror(); // Clear any pending errors.
914 void* self = dlopen(nullptr, RTLD_NOW);
915 ASSERT_TRUE(self != nullptr);
916 ASSERT_TRUE(dlerror() == nullptr);
917
918 void* sym = dlsym(self, "DlSymTestFunction");
919 ASSERT_TRUE(sym != nullptr);
920
921 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
922 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
923
924 Dl_info info;
925 int rc = dladdr(addr, &info);
926 ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
927
928 // Get the name of this executable.
929 const std::string executable_path = android::base::GetExecutablePath();
930
931 // The filename should be that of this executable.
932 char dli_realpath[PATH_MAX];
933 ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
934 ASSERT_STREQ(executable_path.c_str(), dli_realpath);
935
936 // The symbol name should be the symbol we looked up.
937 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
938
939 // The address should be the exact address of the symbol.
940 ASSERT_EQ(info.dli_saddr, sym);
941
942 std::vector<map_record> maps;
943 ASSERT_TRUE(Maps::parse_maps(&maps));
944
945 void* base_address = nullptr;
946 for (const map_record& rec : maps) {
947 if (executable_path == rec.pathname) {
948 base_address = reinterpret_cast<void*>(rec.addr_start);
949 break;
950 }
951 }
952
953 // The base address should be the address we were loaded at.
954 ASSERT_EQ(info.dli_fbase, base_address);
955
956 ASSERT_EQ(0, dlclose(self));
957 }
958
TEST(dlfcn,dlopen_executable_by_absolute_path)959 TEST(dlfcn, dlopen_executable_by_absolute_path) {
960 void* handle1 = dlopen(nullptr, RTLD_NOW);
961 ASSERT_TRUE(handle1 != nullptr) << dlerror();
962
963 void* handle2 = dlopen(android::base::GetExecutablePath().c_str(), RTLD_NOW);
964 ASSERT_TRUE(handle2 != nullptr) << dlerror();
965
966 #if defined(__BIONIC__)
967 ASSERT_EQ(handle1, handle2);
968 #else
969 GTEST_SKIP() << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
970 "it loads a separate copy of the main executable "
971 "on dlopen by absolute path";
972 #endif
973 }
974
975 #define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/" ABI_STRING "/"
976 #if __has_feature(hwaddress_sanitizer)
977 #define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "hwasan/libc.so"
978 #define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/hwasan/libc.so"
979 #define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "hwasan/libc.so"
980 #else
981 #define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
982 #define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/libc.so"
983 #define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
984 #endif
985
TEST(dlfcn,dladdr_libc)986 TEST(dlfcn, dladdr_libc) {
987 #if defined(__GLIBC__)
988 GTEST_SKIP() << "glibc returns libc.so's ldconfig path, which is a symlink (not a realpath)";
989 #endif
990
991 Dl_info info;
992 void* addr = reinterpret_cast<void*>(puts); // An arbitrary libc function.
993 ASSERT_TRUE(dladdr(addr, &info) != 0);
994
995 // Check if libc is in canonical path or in alternate path.
996 const char* expected_path;
997 if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB,
998 info.dli_fname,
999 sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) {
1000 // Platform with emulated architecture. Symlink on ARC++.
1001 expected_path = ALTERNATE_PATH_TO_LIBC;
1002 } else if (strncmp(PATH_TO_BOOTSTRAP_LIBC, info.dli_fname,
1003 sizeof(PATH_TO_BOOTSTRAP_LIBC) - 1) == 0) {
1004 expected_path = PATH_TO_BOOTSTRAP_LIBC;
1005 } else {
1006 // /system/lib is symlink when this test is executed on host.
1007 expected_path = PATH_TO_LIBC;
1008 }
1009 char libc_realpath[PATH_MAX];
1010 ASSERT_TRUE(realpath(expected_path, libc_realpath) != nullptr) << strerror(errno);
1011
1012 ASSERT_STREQ(libc_realpath, info.dli_fname);
1013 // TODO: add check for dfi_fbase
1014 ASSERT_STREQ("puts", info.dli_sname);
1015 ASSERT_EQ(addr, info.dli_saddr);
1016 }
1017
TEST(dlfcn,dladdr_invalid)1018 TEST(dlfcn, dladdr_invalid) {
1019 Dl_info info;
1020
1021 dlerror(); // Clear any pending errors.
1022
1023 #pragma clang diagnostic push
1024 #pragma clang diagnostic ignored "-Wnonnull"
1025 // No symbol corresponding to NULL.
1026 ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
1027 ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
1028 #pragma clang diagnostic pop
1029
1030 // No symbol corresponding to a stack address.
1031 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
1032 ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
1033 }
1034
TEST(dlfcn,dlopen_library_with_only_gnu_hash)1035 TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
1036 dlerror(); // Clear any pending errors.
1037 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
1038 ASSERT_TRUE(handle != nullptr) << dlerror();
1039 auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1040 void* sym = dlsym(handle, "getRandomNumber");
1041 ASSERT_TRUE(sym != nullptr) << dlerror();
1042 int (*fn)(void);
1043 fn = reinterpret_cast<int (*)(void)>(sym);
1044 EXPECT_EQ(4, fn());
1045
1046 Dl_info dlinfo;
1047 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1048
1049 ASSERT_TRUE(fn == dlinfo.dli_saddr);
1050 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1051 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
1052 }
1053
TEST(dlfcn,dlopen_library_with_only_sysv_hash)1054 TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
1055 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
1056 ASSERT_TRUE(handle != nullptr) << dlerror();
1057 auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1058 void* sym = dlsym(handle, "getRandomNumber");
1059 ASSERT_TRUE(sym != nullptr) << dlerror();
1060 int (*fn)(void);
1061 fn = reinterpret_cast<int (*)(void)>(sym);
1062 EXPECT_EQ(4, fn());
1063
1064 Dl_info dlinfo;
1065 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1066
1067 ASSERT_TRUE(fn == dlinfo.dli_saddr);
1068 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1069 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
1070 }
1071
TEST(dlfcn,dlopen_bad_flags)1072 TEST(dlfcn, dlopen_bad_flags) {
1073 dlerror(); // Clear any pending errors.
1074 void* handle;
1075
1076 #if defined(__GLIBC__)
1077 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
1078 handle = dlopen(nullptr, 0);
1079 ASSERT_TRUE(handle == nullptr);
1080 ASSERT_SUBSTR("invalid", dlerror());
1081 #endif
1082
1083 handle = dlopen(nullptr, 0xffffffff);
1084 ASSERT_TRUE(handle == nullptr);
1085 ASSERT_SUBSTR("invalid", dlerror());
1086
1087 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
1088 handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
1089 ASSERT_TRUE(handle != nullptr);
1090 ASSERT_SUBSTR(nullptr, dlerror());
1091 }
1092
TEST(dlfcn,rtld_default_unknown_symbol)1093 TEST(dlfcn, rtld_default_unknown_symbol) {
1094 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
1095 ASSERT_TRUE(addr == nullptr);
1096 }
1097
TEST(dlfcn,rtld_default_known_symbol)1098 TEST(dlfcn, rtld_default_known_symbol) {
1099 void* addr = dlsym(RTLD_DEFAULT, "fopen");
1100 ASSERT_TRUE(addr != nullptr);
1101 }
1102
TEST(dlfcn,rtld_next_unknown_symbol)1103 TEST(dlfcn, rtld_next_unknown_symbol) {
1104 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
1105 ASSERT_TRUE(addr == nullptr);
1106 }
1107
TEST(dlfcn,rtld_next_known_symbol)1108 TEST(dlfcn, rtld_next_known_symbol) {
1109 void* addr = dlsym(RTLD_NEXT, "fopen");
1110 ASSERT_TRUE(addr != nullptr);
1111 }
1112
1113 // Check that RTLD_NEXT of a libc symbol works in dlopened library
TEST(dlfcn,rtld_next_from_library)1114 TEST(dlfcn, rtld_next_from_library) {
1115 void* library_with_fclose = dlopen("libtest_check_rtld_next_from_library.so", RTLD_NOW | RTLD_GLOBAL);
1116 ASSERT_TRUE(library_with_fclose != nullptr) << dlerror();
1117 void* expected_addr = dlsym(RTLD_DEFAULT, "fclose");
1118 ASSERT_TRUE(expected_addr != nullptr) << dlerror();
1119 typedef void* (*get_libc_fclose_ptr_fn_t)();
1120 get_libc_fclose_ptr_fn_t get_libc_fclose_ptr =
1121 reinterpret_cast<get_libc_fclose_ptr_fn_t>(dlsym(library_with_fclose, "get_libc_fclose_ptr"));
1122 ASSERT_TRUE(get_libc_fclose_ptr != nullptr) << dlerror();
1123 ASSERT_EQ(expected_addr, get_libc_fclose_ptr());
1124
1125 dlclose(library_with_fclose);
1126 }
1127
1128
TEST(dlfcn,dlsym_weak_func)1129 TEST(dlfcn, dlsym_weak_func) {
1130 dlerror();
1131 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
1132 ASSERT_TRUE(handle != nullptr);
1133
1134 int (*weak_func)();
1135 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
1136 ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
1137 EXPECT_EQ(42, weak_func());
1138 dlclose(handle);
1139 }
1140
TEST(dlfcn,dlopen_undefined_weak_func)1141 TEST(dlfcn, dlopen_undefined_weak_func) {
1142 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
1143 ASSERT_TRUE(handle != nullptr) << dlerror();
1144 int (*weak_func)();
1145 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
1146 ASSERT_TRUE(weak_func != nullptr) << dlerror();
1147 EXPECT_EQ(6551, weak_func());
1148 dlclose(handle);
1149 }
1150
TEST(dlfcn,dlopen_symlink)1151 TEST(dlfcn, dlopen_symlink) {
1152 DlfcnSymlink symlink("dlopen_symlink");
1153 const std::string symlink_name = android::base::Basename(symlink.get_symlink_path());
1154 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
1155 void* handle2 = dlopen(symlink_name.c_str(), RTLD_NOW);
1156 ASSERT_TRUE(handle1 != nullptr);
1157 ASSERT_TRUE(handle2 != nullptr);
1158 ASSERT_EQ(handle1, handle2);
1159 dlclose(handle1);
1160 dlclose(handle2);
1161 }
1162
1163 // libtest_dlopen_from_ctor_main.so depends on
1164 // libtest_dlopen_from_ctor.so which has a constructor
1165 // that calls dlopen(libc...). This is to test the situation
1166 // described in b/7941716.
TEST(dlfcn,dlopen_dlopen_from_ctor)1167 TEST(dlfcn, dlopen_dlopen_from_ctor) {
1168 #if defined(__GLIBC__)
1169 GTEST_SKIP() << "glibc segfaults if you try to call dlopen from a constructor";
1170 #endif
1171
1172 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
1173 ASSERT_TRUE(handle != nullptr) << dlerror();
1174 dlclose(handle);
1175 }
1176
1177 static std::string g_fini_call_order_str;
1178
register_fini_call(const char * s)1179 static void register_fini_call(const char* s) {
1180 g_fini_call_order_str += s;
1181 }
1182
test_init_fini_call_order_for(const char * libname)1183 static void test_init_fini_call_order_for(const char* libname) {
1184 g_fini_call_order_str.clear();
1185 void* handle = dlopen(libname, RTLD_NOW);
1186 ASSERT_TRUE(handle != nullptr) << dlerror();
1187 typedef int (*get_init_order_number_t)();
1188 get_init_order_number_t get_init_order_number =
1189 reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number"));
1190 ASSERT_EQ(321, get_init_order_number());
1191
1192 typedef void (*set_fini_callback_t)(void (*f)(const char*));
1193 set_fini_callback_t set_fini_callback =
1194 reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback"));
1195 set_fini_callback(register_fini_call);
1196 dlclose(handle);
1197 ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
1198 }
1199
TEST(dlfcn,init_fini_call_order)1200 TEST(dlfcn, init_fini_call_order) {
1201 test_init_fini_call_order_for("libtest_init_fini_order_root.so");
1202 test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
1203 }
1204
TEST(dlfcn,symbol_versioning_use_v1)1205 TEST(dlfcn, symbol_versioning_use_v1) {
1206 void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
1207 ASSERT_TRUE(handle != nullptr) << dlerror();
1208 typedef int (*fn_t)();
1209 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1210 ASSERT_TRUE(fn != nullptr) << dlerror();
1211 ASSERT_EQ(1, fn());
1212 dlclose(handle);
1213 }
1214
TEST(dlfcn,symbol_versioning_use_v2)1215 TEST(dlfcn, symbol_versioning_use_v2) {
1216 void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
1217 ASSERT_TRUE(handle != nullptr) << dlerror();
1218 typedef int (*fn_t)();
1219 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1220 ASSERT_TRUE(fn != nullptr) << dlerror();
1221 ASSERT_EQ(2, fn());
1222 dlclose(handle);
1223 }
1224
TEST(dlfcn,symbol_versioning_use_other_v2)1225 TEST(dlfcn, symbol_versioning_use_other_v2) {
1226 void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
1227 ASSERT_TRUE(handle != nullptr) << dlerror();
1228 typedef int (*fn_t)();
1229 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1230 ASSERT_TRUE(fn != nullptr) << dlerror();
1231 ASSERT_EQ(20, fn());
1232 dlclose(handle);
1233 }
1234
TEST(dlfcn,symbol_versioning_use_other_v3)1235 TEST(dlfcn, symbol_versioning_use_other_v3) {
1236 void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
1237 ASSERT_TRUE(handle != nullptr) << dlerror();
1238 typedef int (*fn_t)();
1239 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1240 ASSERT_TRUE(fn != nullptr) << dlerror();
1241 ASSERT_EQ(3, fn());
1242 dlclose(handle);
1243 }
1244
TEST(dlfcn,symbol_versioning_default_via_dlsym)1245 TEST(dlfcn, symbol_versioning_default_via_dlsym) {
1246 void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1247 ASSERT_TRUE(handle != nullptr) << dlerror();
1248 typedef int (*fn_t)();
1249 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
1250 ASSERT_TRUE(fn != nullptr) << dlerror();
1251 ASSERT_EQ(3, fn()); // the default version is 3
1252 dlclose(handle);
1253 }
1254
TEST(dlfcn,dlvsym_smoke)1255 TEST(dlfcn, dlvsym_smoke) {
1256 #if !defined(ANDROID_HOST_MUSL)
1257 void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1258 ASSERT_TRUE(handle != nullptr) << dlerror();
1259 typedef int (*fn_t)();
1260
1261 {
1262 fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
1263 ASSERT_TRUE(fn == nullptr);
1264 ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
1265 }
1266
1267 {
1268 fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
1269 ASSERT_TRUE(fn != nullptr) << dlerror();
1270 ASSERT_EQ(2, fn());
1271 }
1272
1273 dlclose(handle);
1274 #else
1275 GTEST_SKIP() << "musl doesn't have dlvsym";
1276 #endif
1277 }
1278
1279 // This preempts the implementation from libtest_versioned_lib.so
version_zero_function()1280 extern "C" int version_zero_function() {
1281 return 0;
1282 }
1283
1284 // This preempts the implementation from libtest_versioned_uselibv*.so
version_zero_function2()1285 extern "C" int version_zero_function2() {
1286 return 0;
1287 }
1288
TEST(dlfcn,dt_runpath_smoke)1289 TEST(dlfcn, dt_runpath_smoke) {
1290 void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
1291 ASSERT_TRUE(handle != nullptr) << dlerror();
1292
1293 typedef void *(* dlopen_b_fn)();
1294 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1295 ASSERT_TRUE(fn != nullptr) << dlerror();
1296
1297 void *p = fn();
1298 ASSERT_TRUE(p != nullptr);
1299
1300 dlclose(handle);
1301 }
1302
TEST(dlfcn,dt_runpath_absolute_path)1303 TEST(dlfcn, dt_runpath_absolute_path) {
1304 std::string libpath = GetTestLibRoot() + "/libtest_dt_runpath_d.so";
1305 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1306 ASSERT_TRUE(handle != nullptr) << dlerror();
1307
1308 typedef void *(* dlopen_b_fn)();
1309 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1310 ASSERT_TRUE(fn != nullptr) << dlerror();
1311
1312 void *p = fn();
1313 ASSERT_TRUE(p != nullptr);
1314
1315 dlclose(handle);
1316 }
1317
test_dlclose_after_thread_local_dtor(const char * library_name)1318 static void test_dlclose_after_thread_local_dtor(const char* library_name) {
1319 bool is_dtor_triggered = false;
1320
1321 auto f = [](void* handle, bool* is_dtor_triggered) {
1322 typedef void (*fn_t)(bool*);
1323 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
1324 ASSERT_TRUE(fn != nullptr) << dlerror();
1325
1326 fn(is_dtor_triggered);
1327
1328 ASSERT_TRUE(!*is_dtor_triggered);
1329 };
1330
1331 void* handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1332 ASSERT_TRUE(handle == nullptr);
1333
1334 handle = dlopen(library_name, RTLD_NOW);
1335 ASSERT_TRUE(handle != nullptr) << dlerror();
1336
1337 std::thread t(f, handle, &is_dtor_triggered);
1338 t.join();
1339
1340 ASSERT_TRUE(is_dtor_triggered);
1341 dlclose(handle);
1342
1343 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1344 ASSERT_TRUE(handle == nullptr);
1345 }
1346
TEST(dlfcn,dlclose_after_thread_local_dtor)1347 TEST(dlfcn, dlclose_after_thread_local_dtor) {
1348 test_dlclose_after_thread_local_dtor("libtest_thread_local_dtor.so");
1349 }
1350
TEST(dlfcn,dlclose_after_thread_local_dtor_indirect)1351 TEST(dlfcn, dlclose_after_thread_local_dtor_indirect) {
1352 test_dlclose_after_thread_local_dtor("libtest_indirect_thread_local_dtor.so");
1353 }
1354
test_dlclose_before_thread_local_dtor(const char * library_name)1355 static void test_dlclose_before_thread_local_dtor(const char* library_name) {
1356 bool is_dtor_triggered = false;
1357
1358 auto f = [library_name](bool* is_dtor_triggered) {
1359 void* handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1360 ASSERT_TRUE(handle == nullptr);
1361
1362 handle = dlopen(library_name, RTLD_NOW);
1363 ASSERT_TRUE(handle != nullptr) << dlerror();
1364
1365 typedef void (*fn_t)(bool*);
1366 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
1367 ASSERT_TRUE(fn != nullptr) << dlerror();
1368
1369 fn(is_dtor_triggered);
1370
1371 dlclose(handle);
1372
1373 ASSERT_TRUE(!*is_dtor_triggered);
1374
1375 // Since we have thread_atexit dtors associated with handle - the library should
1376 // still be availabe.
1377 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1378 ASSERT_TRUE(handle != nullptr) << dlerror();
1379 dlclose(handle);
1380 };
1381
1382 void* handle = dlopen(library_name, RTLD_NOW);
1383 ASSERT_TRUE(handle != nullptr) << dlerror();
1384 dlclose(handle);
1385
1386 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1387 ASSERT_TRUE(handle == nullptr);
1388
1389 std::thread t(f, &is_dtor_triggered);
1390 t.join();
1391 #if defined(__BIONIC__)
1392 // ld-android.so unloads unreferenced libraries on pthread_exit()
1393 ASSERT_TRUE(is_dtor_triggered);
1394 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1395 ASSERT_TRUE(handle == nullptr);
1396 #else
1397 // GLIBC does not unload libraries with ref_count = 0 on pthread_exit
1398 ASSERT_TRUE(is_dtor_triggered);
1399 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1400 ASSERT_TRUE(handle != nullptr) << dlerror();
1401 #endif
1402 }
1403
TEST(dlfcn,dlclose_before_thread_local_dtor)1404 TEST(dlfcn, dlclose_before_thread_local_dtor) {
1405 test_dlclose_before_thread_local_dtor("libtest_thread_local_dtor.so");
1406 }
1407
TEST(dlfcn,dlclose_before_thread_local_dtor_indirect)1408 TEST(dlfcn, dlclose_before_thread_local_dtor_indirect) {
1409 test_dlclose_before_thread_local_dtor("libtest_indirect_thread_local_dtor.so");
1410 }
1411
TEST(dlfcn,dlclose_before_thread_local_dtor_multiple_dsos)1412 TEST(dlfcn, dlclose_before_thread_local_dtor_multiple_dsos) {
1413 const constexpr char* library_name = "libtest_indirect_thread_local_dtor.so";
1414
1415 bool is_dtor1_triggered = false;
1416 bool is_dtor2_triggered = false;
1417
1418 std::mutex mtx;
1419 std::condition_variable cv;
1420 void* library_handle = nullptr;
1421 bool thread1_dlopen_complete = false;
1422 bool thread2_thread_local_dtor_initialized = false;
1423 bool thread1_complete = false;
1424
1425 auto f1 = [&]() {
1426 void* handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1427 ASSERT_TRUE(handle == nullptr);
1428
1429 handle = dlopen(library_name, RTLD_NOW);
1430 ASSERT_TRUE(handle != nullptr) << dlerror();
1431 std::unique_lock<std::mutex> lock(mtx);
1432 thread1_dlopen_complete = true;
1433 library_handle = handle;
1434 lock.unlock();
1435 cv.notify_one();
1436
1437 typedef void (*fn_t)(bool*);
1438 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
1439 ASSERT_TRUE(fn != nullptr) << dlerror();
1440
1441 fn(&is_dtor1_triggered);
1442
1443 lock.lock();
1444 cv.wait(lock, [&] { return thread2_thread_local_dtor_initialized; });
1445 lock.unlock();
1446
1447 dlclose(handle);
1448
1449 ASSERT_TRUE(!is_dtor1_triggered);
1450
1451 // Since we have thread_atexit dtors associated with handle - the library should
1452 // still be availabe.
1453 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1454 ASSERT_TRUE(handle != nullptr) << dlerror();
1455 dlclose(handle);
1456 };
1457
1458 auto f2 = [&]() {
1459 std::unique_lock<std::mutex> lock(mtx);
1460 cv.wait(lock, [&] { return thread1_dlopen_complete; });
1461 void* handle = library_handle;
1462 lock.unlock();
1463
1464 typedef void (*fn_t)(bool*);
1465 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable2"));
1466 ASSERT_TRUE(fn != nullptr) << dlerror();
1467
1468 fn(&is_dtor2_triggered);
1469
1470 lock.lock();
1471 thread2_thread_local_dtor_initialized = true;
1472 lock.unlock();
1473 cv.notify_one();
1474
1475 lock.lock();
1476 cv.wait(lock, [&] { return thread1_complete; });
1477 lock.unlock();
1478
1479 ASSERT_TRUE(!is_dtor2_triggered);
1480 };
1481
1482 void* handle = dlopen(library_name, RTLD_NOW);
1483 ASSERT_TRUE(handle != nullptr) << dlerror();
1484 dlclose(handle);
1485
1486 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1487 ASSERT_TRUE(handle == nullptr);
1488
1489 std::thread t1(f1);
1490 std::thread t2(f2);
1491 t1.join();
1492 ASSERT_TRUE(is_dtor1_triggered);
1493 ASSERT_TRUE(!is_dtor2_triggered);
1494
1495 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1496 ASSERT_TRUE(handle != nullptr) << dlerror();
1497 dlclose(handle);
1498
1499 std::unique_lock<std::mutex> lock(mtx);
1500 thread1_complete = true;
1501 lock.unlock();
1502 cv.notify_one();
1503
1504 t2.join();
1505 ASSERT_TRUE(is_dtor2_triggered);
1506
1507 #if defined(__BIONIC__)
1508 // ld-android.so unloads unreferenced libraries on pthread_exit()
1509 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1510 ASSERT_TRUE(handle == nullptr);
1511 #else
1512 // GLIBC does not unload libraries with ref_count = 0 on pthread_exit
1513 handle = dlopen(library_name, RTLD_NOW | RTLD_NOLOAD);
1514 ASSERT_TRUE(handle != nullptr) << dlerror();
1515 #endif
1516 }
1517
TEST(dlfcn,RTLD_macros)1518 TEST(dlfcn, RTLD_macros) {
1519 #if !defined(RTLD_LOCAL)
1520 #error no RTLD_LOCAL
1521 #elif !defined(RTLD_LAZY)
1522 #error no RTLD_LAZY
1523 #elif !defined(RTLD_NOW)
1524 #error no RTLD_NOW
1525 #elif !defined(RTLD_NOLOAD)
1526 #error no RTLD_NOLOAD
1527 #elif !defined(RTLD_GLOBAL)
1528 #error no RTLD_GLOBAL
1529 #elif !defined(RTLD_NODELETE)
1530 #error no RTLD_NODELETE
1531 #endif
1532 }
1533
1534 // Bionic specific tests
1535 #if defined(__BIONIC__)
1536
1537 #if defined(__arm__)
1538
validate_compatibility_of_native_library(const std::string & soname,const std::string & path)1539 void validate_compatibility_of_native_library(const std::string& soname, const std::string& path) {
1540 // Grab the dynamic section in text form...
1541 ExecTestHelper eth;
1542 eth.SetArgs({"readelf", "-dW", path.c_str(), nullptr});
1543 eth.Run([&]() { execvpe("readelf", eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
1544 std::string output = eth.GetOutput();
1545
1546 // Check that there *is* a legacy DT_HASH (not just a GNU hash)...
1547 ASSERT_TRUE(std::regex_search(output, std::regex("\\(HASH\\)"))) << output;
1548 // Check that there is no DT_ANDROID_REL or DT_ANDROID_RELA...
1549 ASSERT_FALSE(std::regex_search(output, std::regex("\\(ANDROID_REL\\)"))) << output;
1550 ASSERT_FALSE(std::regex_search(output, std::regex("\\(ANDROID_RELA\\)"))) << output;
1551
1552 // Check that we have regular non-packed relocations.
1553 // libdl.so is simple enough that it doesn't have any relocations.
1554 ASSERT_TRUE(std::regex_search(output, std::regex("\\(RELA?\\)")) || soname == "libdl.so")
1555 << output;
1556 }
1557
validate_compatibility_of_native_library(const std::string & soname)1558 void validate_compatibility_of_native_library(const std::string& soname) {
1559 // On the systems with emulation system libraries would be of different
1560 // architecture. Try to use alternate paths first.
1561 std::string path = std::string(ALTERNATE_PATH_TO_SYSTEM_LIB) + soname;
1562 if (access(path.c_str(), R_OK) != 0) {
1563 path = std::string(PATH_TO_SYSTEM_LIB) + soname;
1564 ASSERT_EQ(0, access(path.c_str(), R_OK));
1565 }
1566 validate_compatibility_of_native_library(soname, path);
1567 }
1568
1569 // This is a test for app compatibility workaround for arm apps
1570 // affected by http://b/24465209
TEST(dlext,compat_elf_hash_and_relocation_tables)1571 TEST(dlext, compat_elf_hash_and_relocation_tables) {
1572 validate_compatibility_of_native_library("libc.so");
1573 validate_compatibility_of_native_library("liblog.so");
1574 validate_compatibility_of_native_library("libstdc++.so");
1575 validate_compatibility_of_native_library("libdl.so");
1576 validate_compatibility_of_native_library("libm.so");
1577 validate_compatibility_of_native_library("libz.so");
1578 validate_compatibility_of_native_library("libjnigraphics.so");
1579 }
1580
1581 #endif // defined(__arm__)
1582
TEST(dlfcn,dlopen_invalid_rw_load_segment)1583 TEST(dlfcn, dlopen_invalid_rw_load_segment) {
1584 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-rw_load_segment.so";
1585 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1586 ASSERT_TRUE(handle == nullptr);
1587 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed";
1588 ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1589 }
1590
TEST(dlfcn,dlopen_invalid_unaligned_shdr_offset)1591 TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
1592 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-unaligned_shdr_offset.so";
1593
1594 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1595 ASSERT_TRUE(handle == nullptr);
1596 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: ";
1597 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1598 }
1599
TEST(dlfcn,dlopen_invalid_zero_shentsize)1600 TEST(dlfcn, dlopen_invalid_zero_shentsize) {
1601 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shentsize.so";
1602
1603 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1604 ASSERT_TRUE(handle == nullptr);
1605 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has unsupported e_shentsize: 0x0 (expected 0x";
1606 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1607 }
1608
TEST(dlfcn,dlopen_invalid_zero_shstrndx)1609 TEST(dlfcn, dlopen_invalid_zero_shstrndx) {
1610 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shstrndx.so";
1611
1612 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1613 ASSERT_TRUE(handle == nullptr);
1614 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid e_shstrndx";
1615 ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1616 }
1617
TEST(dlfcn,dlopen_invalid_empty_shdr_table)1618 TEST(dlfcn, dlopen_invalid_empty_shdr_table) {
1619 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-empty_shdr_table.so";
1620
1621 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1622 ASSERT_TRUE(handle == nullptr);
1623 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has no section headers";
1624 ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1625 }
1626
TEST(dlfcn,dlopen_invalid_zero_shdr_table_offset)1627 TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
1628 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shdr_table_offset.so";
1629
1630 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1631 ASSERT_TRUE(handle == nullptr);
1632 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: 0/";
1633 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1634 }
1635
TEST(dlfcn,dlopen_invalid_zero_shdr_table_content)1636 TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
1637 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shdr_table_content.so";
1638
1639 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1640 ASSERT_TRUE(handle == nullptr);
1641 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" .dynamic section header was not found";
1642 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1643 }
1644
TEST(dlfcn,dlopen_invalid_textrels)1645 TEST(dlfcn, dlopen_invalid_textrels) {
1646 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-textrels.so";
1647
1648 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1649 ASSERT_TRUE(handle == nullptr);
1650 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1651 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1652 }
1653
TEST(dlfcn,dlopen_invalid_textrels2)1654 TEST(dlfcn, dlopen_invalid_textrels2) {
1655 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-textrels2.so";
1656
1657 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1658 ASSERT_TRUE(handle == nullptr);
1659 std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1660 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1661 }
1662
TEST(dlfcn,dlopen_invalid_local_tls)1663 TEST(dlfcn, dlopen_invalid_local_tls) {
1664 #if defined(__riscv)
1665 // This is a test for bad gold behavior, and gold doesn't support riscv64.
1666 #else
1667 const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-local-tls.so";
1668
1669 void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1670 ASSERT_TRUE(handle == nullptr);
1671 #if defined(__arm__)
1672 const char* referent = "local section";
1673 #else
1674 const char* referent = "local symbol \"tls_var_2\"";
1675 #endif
1676 std::string expected_dlerror = std::string("dlopen failed: unexpected TLS reference to ") +
1677 referent + " in \"" + libpath + "\"";
1678 ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1679 #endif
1680 }
1681
TEST(dlfcn,dlopen_df_1_global)1682 TEST(dlfcn, dlopen_df_1_global) {
1683 void* handle = dlopen("libtest_dlopen_df_1_global.so", RTLD_NOW);
1684 ASSERT_TRUE(handle != nullptr) << dlerror();
1685 }
1686
TEST(dlfcn,segment_gap)1687 TEST(dlfcn, segment_gap) {
1688 void* handle = dlopen("libsegment_gap_outer.so", RTLD_NOW);
1689 ASSERT_TRUE(handle != nullptr) << dlerror();
1690
1691 auto get_inner = reinterpret_cast<void* (*)()>(dlsym(handle, "get_inner"));
1692 void* inner = get_inner();
1693 (void)inner;
1694
1695 #if __arm__
1696 int count;
1697 _Unwind_Ptr outer_exidx = dl_unwind_find_exidx(reinterpret_cast<_Unwind_Ptr>(get_inner), &count);
1698 _Unwind_Ptr inner_exidx = dl_unwind_find_exidx(reinterpret_cast<_Unwind_Ptr>(inner), &count);
1699 EXPECT_NE(0u, outer_exidx);
1700 EXPECT_NE(0u, inner_exidx);
1701 EXPECT_NE(inner_exidx, outer_exidx);
1702 #endif
1703
1704 Dl_info info;
1705 int rc = dladdr(inner, &info);
1706 ASSERT_NE(rc, 0);
1707
1708 EXPECT_NE(nullptr, strstr(info.dli_fname, "libsegment_gap_inner.so"));
1709 }
1710
1711 #endif
1712