dlfcn_test.cpp revision 554374693408cd7c74d0cae596fca7349661edea
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 <libgen.h> 21#include <limits.h> 22#include <stdio.h> 23#include <stdint.h> 24 25#include "private/ScopeGuard.h" 26 27#include <string> 28 29#include "utils.h" 30 31#define ASSERT_SUBSTR(needle, haystack) \ 32 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) 33 34 35static bool g_called = false; 36extern "C" void DlSymTestFunction() { 37 g_called = true; 38} 39 40static int g_ctor_function_called = 0; 41static int g_ctor_argc = 0; 42static char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF); 43static char** g_ctor_envp = g_ctor_envp; 44 45extern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor)); 46 47extern "C" void ctor_function(int argc, char** argv, char** envp) { 48 g_ctor_function_called = 17; 49 g_ctor_argc = argc; 50 g_ctor_argv = argv; 51 g_ctor_envp = envp; 52} 53 54TEST(dlfcn, ctor_function_call) { 55 ASSERT_EQ(17, g_ctor_function_called); 56 ASSERT_TRUE(g_ctor_argc = get_argc()); 57 ASSERT_TRUE(g_ctor_argv = get_argv()); 58 ASSERT_TRUE(g_ctor_envp = get_envp()); 59} 60 61TEST(dlfcn, dlsym_in_executable) { 62 dlerror(); // Clear any pending errors. 63 void* self = dlopen(nullptr, RTLD_NOW); 64 ASSERT_TRUE(self != nullptr); 65 ASSERT_TRUE(dlerror() == nullptr); 66 67 void* sym = dlsym(self, "DlSymTestFunction"); 68 ASSERT_TRUE(sym != nullptr); 69 70 void (*function)() = reinterpret_cast<void(*)()>(sym); 71 72 g_called = false; 73 function(); 74 ASSERT_TRUE(g_called); 75 76 ASSERT_EQ(0, dlclose(self)); 77} 78 79TEST(dlfcn, dlsym_from_sofile) { 80 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL); 81 ASSERT_TRUE(handle != nullptr) << dlerror(); 82 83 // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT) 84 void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol"); 85 ASSERT_TRUE(symbol == nullptr); 86 ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror()); 87 88 typedef int* (*fn_t)(); 89 fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT = 90 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); 91 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror(); 92 93 int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT(); 94 ASSERT_TRUE(ptr != nullptr) << dlerror(); 95 ASSERT_EQ(42, *ptr); 96 97 fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT = 98 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT")); 99 ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror(); 100 101 ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT(); 102 ASSERT_TRUE(ptr != nullptr) << dlerror(); 103 ASSERT_EQ(44, *ptr); 104 105 fn_t lookup_dlsym_symbol_using_RTLD_NEXT = 106 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT")); 107 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror(); 108 109 ptr = lookup_dlsym_symbol_using_RTLD_NEXT(); 110 ASSERT_TRUE(ptr != nullptr) << dlerror(); 111 ASSERT_EQ(43, *ptr); 112 113 dlclose(handle); 114} 115 116TEST(dlfcn, dlsym_from_sofile_with_preload) { 117 void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL); 118 ASSERT_TRUE(preload != nullptr) << dlerror(); 119 120 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL); 121 ASSERT_TRUE(handle != nullptr) << dlerror(); 122 123 // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT) 124 void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol"); 125 ASSERT_TRUE(symbol == nullptr); 126 ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror()); 127 128 typedef int* (*fn_t)(); 129 fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT = 130 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); 131 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror(); 132 133 int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT(); 134 ASSERT_TRUE(ptr != nullptr) << dlerror(); 135 ASSERT_EQ(42, *ptr); 136 137 fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT = 138 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT")); 139 ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror(); 140 141 ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT(); 142 ASSERT_TRUE(ptr != nullptr) << dlerror(); 143 ASSERT_EQ(44, *ptr); 144 145 fn_t lookup_dlsym_symbol_using_RTLD_NEXT = 146 reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT")); 147 ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror(); 148 149 ptr = lookup_dlsym_symbol_using_RTLD_NEXT(); 150 ASSERT_TRUE(ptr != nullptr) << dlerror(); 151 ASSERT_EQ(43, *ptr); 152 153 dlclose(handle); 154 dlclose(preload); 155} 156 157TEST(dlfcn, dlsym_handle_global_sym) { 158 // check that we do not look into global group 159 // when looking up symbol by handle 160 void* handle = dlopen("libtest_empty.so", RTLD_NOW); 161 dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL); 162 void* sym = dlsym(handle, "getRandomNumber"); 163 ASSERT_TRUE(sym == nullptr); 164 ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror()); 165 166 sym = dlsym(handle, "DlSymTestFunction"); 167 ASSERT_TRUE(sym == nullptr); 168 ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror()); 169 dlclose(handle); 170} 171 172TEST(dlfcn, dlsym_with_dependencies) { 173 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); 174 ASSERT_TRUE(handle != nullptr); 175 dlerror(); 176 // This symbol is in DT_NEEDED library. 177 void* sym = dlsym(handle, "getRandomNumber"); 178 ASSERT_TRUE(sym != nullptr) << dlerror(); 179 int (*fn)(void); 180 fn = reinterpret_cast<int (*)(void)>(sym); 181 EXPECT_EQ(4, fn()); 182 dlclose(handle); 183} 184 185TEST(dlfcn, dlopen_noload) { 186 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD); 187 ASSERT_TRUE(handle == nullptr); 188 handle = dlopen("libtest_simple.so", RTLD_NOW); 189 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD); 190 ASSERT_TRUE(handle != nullptr); 191 ASSERT_TRUE(handle2 != nullptr); 192 ASSERT_TRUE(handle == handle2); 193 ASSERT_EQ(0, dlclose(handle)); 194 ASSERT_EQ(0, dlclose(handle2)); 195} 196 197TEST(dlfcn, dlopen_by_soname) { 198 static const char* soname = "libdlext_test_soname.so"; 199 static const char* filename = "libdlext_test_different_soname.so"; 200 // 1. Make sure there is no library with soname in default search path 201 void* handle = dlopen(soname, RTLD_NOW); 202 ASSERT_TRUE(handle == nullptr); 203 204 // 2. Load a library using filename 205 handle = dlopen(filename, RTLD_NOW); 206 ASSERT_TRUE(handle != nullptr) << dlerror(); 207 208 // 3. Find library by soname 209 void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD); 210 ASSERT_TRUE(handle_soname != nullptr) << dlerror(); 211 ASSERT_EQ(handle, handle_soname); 212 213 // 4. RTLD_NOLOAD should still work with filename 214 void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD); 215 ASSERT_TRUE(handle_filename != nullptr) << dlerror(); 216 ASSERT_EQ(handle, handle_filename); 217 218 dlclose(handle_filename); 219 dlclose(handle_soname); 220 dlclose(handle); 221} 222 223// mips doesn't support ifuncs 224#if !defined(__mips__) 225TEST(dlfcn, ifunc) { 226 typedef const char* (*fn_ptr)(); 227 228 // ifunc's choice depends on whether IFUNC_CHOICE has a value 229 // first check the set case 230 setenv("IFUNC_CHOICE", "set", 1); 231 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); 232 ASSERT_TRUE(handle != nullptr); 233 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); 234 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); 235 ASSERT_TRUE(foo_ptr != nullptr); 236 ASSERT_TRUE(foo_library_ptr != nullptr); 237 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0); 238 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0); 239 dlclose(handle); 240 241 // then check the unset case 242 unsetenv("IFUNC_CHOICE"); 243 handle = dlopen("libtest_ifunc.so", RTLD_NOW); 244 ASSERT_TRUE(handle != nullptr); 245 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); 246 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); 247 ASSERT_TRUE(foo_ptr != nullptr); 248 ASSERT_TRUE(foo_library_ptr != nullptr); 249 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); 250 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); 251 dlclose(handle); 252} 253 254TEST(dlfcn, ifunc_ctor_call) { 255 typedef const char* (*fn_ptr)(); 256 257 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); 258 ASSERT_TRUE(handle != nullptr) << dlerror(); 259 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative")); 260 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 261 ASSERT_STREQ("false", is_ctor_called()); 262 263 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot")); 264 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 265 ASSERT_STREQ("true", is_ctor_called()); 266 dlclose(handle); 267} 268 269TEST(dlfcn, ifunc_ctor_call_rtld_lazy) { 270 typedef const char* (*fn_ptr)(); 271 272 void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY); 273 ASSERT_TRUE(handle != nullptr) << dlerror(); 274 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative")); 275 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 276 ASSERT_STREQ("false", is_ctor_called()); 277 278 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot")); 279 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 280 ASSERT_STREQ("true", is_ctor_called()); 281 dlclose(handle); 282} 283#endif 284 285TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { 286 // This is the structure of the test library and 287 // its dt_needed libraries 288 // libtest_relo_check_dt_needed_order.so 289 // | 290 // +-> libtest_relo_check_dt_needed_order_1.so 291 // | 292 // +-> libtest_relo_check_dt_needed_order_2.so 293 // 294 // The root library references relo_test_get_answer_lib - which is defined 295 // in both dt_needed libraries, the correct relocation should 296 // use the function defined in libtest_relo_check_dt_needed_order_1.so 297 void* handle = nullptr; 298 auto guard = make_scope_guard([&]() { 299 dlclose(handle); 300 }); 301 302 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW); 303 ASSERT_TRUE(handle != nullptr) << dlerror(); 304 305 typedef int (*fn_t) (void); 306 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer")); 307 ASSERT_TRUE(fn != nullptr) << dlerror(); 308 ASSERT_EQ(1, fn()); 309} 310 311TEST(dlfcn, dlopen_check_order_dlsym) { 312 // Here is how the test library and its dt_needed 313 // libraries are arranged 314 // 315 // libtest_check_order_children.so 316 // | 317 // +-> ..._1_left.so 318 // | | 319 // | +-> ..._a.so 320 // | | 321 // | +-> ...r_b.so 322 // | 323 // +-> ..._2_right.so 324 // | | 325 // | +-> ..._d.so 326 // | | 327 // | +-> ..._b.so 328 // | 329 // +-> ..._3_c.so 330 // 331 // load order should be (1, 2, 3, a, b, d) 332 // 333 // get_answer() is defined in (2, 3, a, b, c) 334 // get_answer2() is defined in (b, d) 335 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"); 336 ASSERT_TRUE(sym == nullptr); 337 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL); 338 ASSERT_TRUE(handle != nullptr) << dlerror(); 339 typedef int (*fn_t) (void); 340 fn_t fn, fn2; 341 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer")); 342 ASSERT_TRUE(fn != nullptr) << dlerror(); 343 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2")); 344 ASSERT_TRUE(fn2 != nullptr) << dlerror(); 345 346 ASSERT_EQ(42, fn()); 347 ASSERT_EQ(43, fn2()); 348 dlclose(handle); 349} 350 351TEST(dlfcn, dlopen_check_order_reloc_siblings) { 352 // This is how this one works: 353 // we lookup and call get_answer which is defined in '_2.so' 354 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so' 355 // the correct _impl() is implemented by '_a.so'; 356 // 357 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?) 358 // 359 // Here is the picture: 360 // 361 // libtest_check_order_reloc_siblings.so 362 // | 363 // +-> ..._1.so <- empty 364 // | | 365 // | +-> ..._a.so <- exports correct answer_impl() 366 // | | 367 // | +-> ..._b.so <- every other letter exporting incorrect one. 368 // | 369 // +-> ..._2.so <- empty 370 // | | 371 // | +-> ..._c.so 372 // | | 373 // | +-> ..._d.so 374 // | 375 // +-> ..._3.so <- empty 376 // | 377 // +-> ..._e.so 378 // | 379 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl(); 380 // implements incorrect get_answer_impl() 381 382 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 383 ASSERT_TRUE(handle == nullptr); 384#ifdef __BIONIC__ 385 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 386 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 387#endif 388 389 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 390 ASSERT_TRUE(handle != nullptr) << dlerror(); 391 392 typedef int (*fn_t) (void); 393 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer")); 394 ASSERT_TRUE(fn != nullptr) << dlerror(); 395 ASSERT_EQ(42, fn()); 396 397 ASSERT_EQ(0, dlclose(handle)); 398} 399 400TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) { 401 // This test uses the same library as dlopen_check_order_reloc_siblings. 402 // Unlike dlopen_check_order_reloc_siblings it preloads 403 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to 404 // dlopen(libtest_check_order_reloc_siblings.so) 405 406 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 407 ASSERT_TRUE(handle == nullptr); 408 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD); 409 ASSERT_TRUE(handle == nullptr); 410 411 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL); 412 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror(); 413 414 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 415 ASSERT_TRUE(handle != nullptr) << dlerror(); 416 417 ASSERT_EQ(0, dlclose(handle_for_1)); 418 419 typedef int (*fn_t) (void); 420 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer")); 421 ASSERT_TRUE(fn != nullptr) << dlerror(); 422 ASSERT_EQ(42, fn()); 423 424 ASSERT_EQ(0, dlclose(handle)); 425} 426 427TEST(dlfcn, dlopen_check_order_reloc_grandchild) { 428 // This is how this one works: 429 // we lookup and call grandchild_get_answer which is defined in '_2.so' 430 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so' 431 // the correct _impl() is implemented by '_c_1.so'; 432 // 433 // Here is the picture of subtree: 434 // 435 // libtest_check_order_reloc_siblings.so 436 // | 437 // +-> ..._2.so <- grandchild_get_answer() 438 // | 439 // +-> ..._c.so <- empty 440 // | | 441 // | +-> _c_1.so <- exports correct answer_impl() 442 // | | 443 // | +-> _c_2.so <- exports incorrect answer_impl() 444 // | 445 // +-> ..._d.so <- empty 446 447 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 448 ASSERT_TRUE(handle == nullptr); 449#ifdef __BIONIC__ 450 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 451 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 452#endif 453 454 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 455 ASSERT_TRUE(handle != nullptr) << dlerror(); 456 457 typedef int (*fn_t) (void); 458 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer")); 459 ASSERT_TRUE(fn != nullptr) << dlerror(); 460 ASSERT_EQ(42, fn()); 461 462 ASSERT_EQ(0, dlclose(handle)); 463} 464 465TEST(dlfcn, dlopen_check_order_reloc_nephew) { 466 // This is how this one works: 467 // we lookup and call nephew_get_answer which is defined in '_2.so' 468 // and in turn calls external get_answer_impl() defined in '_[a-f].so' 469 // the correct _impl() is implemented by '_a.so'; 470 // 471 // Here is the picture: 472 // 473 // libtest_check_order_reloc_siblings.so 474 // | 475 // +-> ..._1.so <- empty 476 // | | 477 // | +-> ..._a.so <- exports correct answer_impl() 478 // | | 479 // | +-> ..._b.so <- every other letter exporting incorrect one. 480 // | 481 // +-> ..._2.so <- empty 482 // | | 483 // | +-> ..._c.so 484 // | | 485 // | +-> ..._d.so 486 // | 487 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl(); 488 // | 489 // +-> ..._e.so 490 // | 491 // +-> ..._f.so 492 493 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 494 ASSERT_TRUE(handle == nullptr); 495#ifdef __BIONIC__ 496 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 497 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 498#endif 499 500 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 501 ASSERT_TRUE(handle != nullptr) << dlerror(); 502 503 typedef int (*fn_t) (void); 504 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer")); 505 ASSERT_TRUE(fn != nullptr) << dlerror(); 506 ASSERT_EQ(42, fn()); 507 508 ASSERT_EQ(0, dlclose(handle)); 509} 510 511TEST(dlfcn, check_unload_after_reloc) { 512 // This is how this one works: 513 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child 514 // | 515 // +-> libtest_two_parents_child 516 // 517 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child 518 // | 519 // +-> libtest_two_parents_child 520 // 521 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so 522 // as a second step it dlopens parent2 and dlcloses parent1... 523 524 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL); 525 ASSERT_TRUE(handle != nullptr) << dlerror(); 526 527 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL); 528 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 529 530 typedef int (*fn_t) (void); 531 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer")); 532 ASSERT_TRUE(fn != nullptr) << dlerror(); 533 ASSERT_EQ(42, fn()); 534 535 ASSERT_EQ(0, dlclose(handle)); 536 537 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); 538 ASSERT_TRUE(handle != nullptr); 539 ASSERT_EQ(0, dlclose(handle)); 540 541 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer")); 542 ASSERT_TRUE(fn != nullptr) << dlerror(); 543 ASSERT_EQ(42, fn()); 544 545 ASSERT_EQ(0, dlclose(handle2)); 546 547 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); 548 ASSERT_TRUE(handle == nullptr); 549} 550 551extern "C" int check_order_reloc_root_get_answer_impl() { 552 return 42; 553} 554 555TEST(dlfcn, dlopen_check_order_reloc_main_executable) { 556 // This is how this one works: 557 // we lookup and call get_answer3 which is defined in 'root.so' 558 // and in turn calls external root_get_answer_impl() defined in _2.so and 559 // above the correct _impl() is one in the executable. 560 // 561 // libtest_check_order_reloc_root.so 562 // | 563 // +-> ..._1.so <- empty 564 // | 565 // +-> ..._2.so <- gives incorrect answer for answer_main_impl() 566 // 567 568 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD); 569 ASSERT_TRUE(handle == nullptr); 570#ifdef __BIONIC__ 571 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 572 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 573#endif 574 575 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL); 576 ASSERT_TRUE(handle != nullptr) << dlerror(); 577 578 typedef int (*fn_t) (void); 579 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer")); 580 ASSERT_TRUE(fn != nullptr) << dlerror(); 581 ASSERT_EQ(42, fn()); 582 583 ASSERT_EQ(0, dlclose(handle)); 584} 585 586TEST(dlfcn, dlopen_check_rtld_local) { 587 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 588 ASSERT_TRUE(sym == nullptr); 589 590 // implicit RTLD_LOCAL 591 void* handle = dlopen("libtest_simple.so", RTLD_NOW); 592 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 593 ASSERT_TRUE(sym == nullptr); 594 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); 595 sym = dlsym(handle, "dlopen_testlib_simple_func"); 596 ASSERT_TRUE(sym != nullptr); 597 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 598 dlclose(handle); 599 600 // explicit RTLD_LOCAL 601 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL); 602 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 603 ASSERT_TRUE(sym == nullptr); 604 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); 605 sym = dlsym(handle, "dlopen_testlib_simple_func"); 606 ASSERT_TRUE(sym != nullptr); 607 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 608 dlclose(handle); 609} 610 611TEST(dlfcn, dlopen_check_rtld_global) { 612 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 613 ASSERT_TRUE(sym == nullptr); 614 615 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); 616 ASSERT_TRUE(handle != nullptr) << dlerror(); 617 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 618 ASSERT_TRUE(sym != nullptr) << dlerror(); 619 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 620 dlclose(handle); 621 622 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that 623 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 624 ASSERT_EQ(sym, sym_after_dlclose); 625 626 // Check if dlsym() for main program's handle searches RTLD_GLOBAL 627 // shared libraries after symbol was not found in the main executable 628 // and dependent libraries. 629 void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW); 630 sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func"); 631 ASSERT_TRUE(sym != nullptr) << dlerror(); 632 633 dlclose(handle_for_main_executable); 634} 635 636// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> 637// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> 638// libtest_with_dependency_loop_a.so 639TEST(dlfcn, dlopen_check_loop) { 640 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); 641 ASSERT_TRUE(handle != nullptr) << dlerror(); 642 void* f = dlsym(handle, "dlopen_test_loopy_function"); 643 ASSERT_TRUE(f != nullptr) << dlerror(); 644 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)()); 645 ASSERT_EQ(0, dlclose(handle)); 646 647 // dlopen second time to make sure that the library was unloaded correctly 648 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD); 649 ASSERT_TRUE(handle == nullptr); 650#ifdef __BIONIC__ 651 ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 652#else 653 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 654 ASSERT_TRUE(dlerror() == nullptr); 655#endif 656 657 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD); 658 ASSERT_TRUE(handle == nullptr); 659} 660 661TEST(dlfcn, dlopen_nodelete) { 662 static bool is_unloaded = false; 663 664 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE); 665 ASSERT_TRUE(handle != nullptr) << dlerror(); 666 void (*set_unload_flag_ptr)(bool*); 667 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr")); 668 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 669 set_unload_flag_ptr(&is_unloaded); 670 671 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 672 ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); 673 ASSERT_EQ(1729U, *taxicab_number); 674 *taxicab_number = 2; 675 676 dlclose(handle); 677 ASSERT_TRUE(!is_unloaded); 678 679 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 680 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number); 681 ASSERT_EQ(2U, *taxicab_number_after_dlclose); 682 683 684 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW); 685 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 686 ASSERT_EQ(taxicab_number2, taxicab_number); 687 688 ASSERT_EQ(2U, *taxicab_number2); 689 690 dlclose(handle); 691 ASSERT_TRUE(!is_unloaded); 692} 693 694TEST(dlfcn, dlopen_nodelete_on_second_dlopen) { 695 static bool is_unloaded = false; 696 697 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW); 698 ASSERT_TRUE(handle != nullptr) << dlerror(); 699 void (*set_unload_flag_ptr)(bool*); 700 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr")); 701 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 702 set_unload_flag_ptr(&is_unloaded); 703 704 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number")); 705 ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); 706 707 ASSERT_EQ(1729U, *taxicab_number); 708 *taxicab_number = 2; 709 710 // This RTLD_NODELETE should be ignored 711 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE); 712 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 713 ASSERT_EQ(handle, handle1); 714 715 dlclose(handle1); 716 dlclose(handle); 717 718 ASSERT_TRUE(is_unloaded); 719} 720 721TEST(dlfcn, dlopen_nodelete_dt_flags_1) { 722 static bool is_unloaded = false; 723 724 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW); 725 ASSERT_TRUE(handle != nullptr) << dlerror(); 726 void (*set_unload_flag_ptr)(bool*); 727 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr")); 728 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 729 set_unload_flag_ptr(&is_unloaded); 730 731 dlclose(handle); 732 ASSERT_TRUE(!is_unloaded); 733} 734 735TEST(dlfcn, dlsym_df_1_global) { 736 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); 737 ASSERT_TRUE(handle != nullptr) << dlerror(); 738 int (*get_answer)(); 739 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer")); 740 ASSERT_TRUE(get_answer != nullptr) << dlerror(); 741 ASSERT_EQ(42, get_answer()); 742 ASSERT_EQ(0, dlclose(handle)); 743} 744 745TEST(dlfcn, dlopen_failure) { 746 void* self = dlopen("/does/not/exist", RTLD_NOW); 747 ASSERT_TRUE(self == nullptr); 748#if defined(__BIONIC__) 749 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror()); 750#else 751 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror()); 752#endif 753} 754 755static void* ConcurrentDlErrorFn(void*) { 756 dlopen("/child/thread", RTLD_NOW); 757 return reinterpret_cast<void*>(strdup(dlerror())); 758} 759 760TEST(dlfcn, dlerror_concurrent) { 761 dlopen("/main/thread", RTLD_NOW); 762 const char* main_thread_error = dlerror(); 763 ASSERT_SUBSTR("/main/thread", main_thread_error); 764 765 pthread_t t; 766 ASSERT_EQ(0, pthread_create(&t, nullptr, ConcurrentDlErrorFn, nullptr)); 767 void* result; 768 ASSERT_EQ(0, pthread_join(t, &result)); 769 char* child_thread_error = static_cast<char*>(result); 770 ASSERT_SUBSTR("/child/thread", child_thread_error); 771 free(child_thread_error); 772 773 ASSERT_SUBSTR("/main/thread", main_thread_error); 774} 775 776TEST(dlfcn, dlsym_failures) { 777 dlerror(); // Clear any pending errors. 778 void* self = dlopen(nullptr, RTLD_NOW); 779 ASSERT_TRUE(self != nullptr); 780 ASSERT_TRUE(dlerror() == nullptr); 781 782 void* sym; 783 784#if defined(__BIONIC__) && !defined(__LP64__) 785 // RTLD_DEFAULT in lp32 bionic is not (void*)0 786 // so it can be distinguished from the NULL handle. 787 sym = dlsym(nullptr, "test"); 788 ASSERT_TRUE(sym == nullptr); 789 ASSERT_STREQ("dlsym failed: library handle is null", dlerror()); 790#endif 791 792 // Symbol that doesn't exist. 793 sym = dlsym(self, "ThisSymbolDoesNotExist"); 794 ASSERT_TRUE(sym == nullptr); 795 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror()); 796 797 ASSERT_EQ(0, dlclose(self)); 798} 799 800TEST(dlfcn, dladdr_executable) { 801 dlerror(); // Clear any pending errors. 802 void* self = dlopen(nullptr, RTLD_NOW); 803 ASSERT_TRUE(self != nullptr); 804 ASSERT_TRUE(dlerror() == nullptr); 805 806 void* sym = dlsym(self, "DlSymTestFunction"); 807 ASSERT_TRUE(sym != nullptr); 808 809 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address. 810 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2); 811 812 Dl_info info; 813 int rc = dladdr(addr, &info); 814 ASSERT_NE(rc, 0); // Zero on error, non-zero on success. 815 816 // Get the name of this executable. 817 const std::string& executable_path = get_executable_path(); 818 819 // The filename should be that of this executable. 820 char dli_realpath[PATH_MAX]; 821 ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr); 822 ASSERT_STREQ(executable_path.c_str(), dli_realpath); 823 824 // The symbol name should be the symbol we looked up. 825 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); 826 827 // The address should be the exact address of the symbol. 828 ASSERT_EQ(info.dli_saddr, sym); 829 830 std::vector<map_record> maps; 831 ASSERT_TRUE(Maps::parse_maps(&maps)); 832 833 void* base_address = nullptr; 834 for (const map_record& rec : maps) { 835 if (executable_path == rec.pathname) { 836 base_address = reinterpret_cast<void*>(rec.addr_start); 837 break; 838 } 839 } 840 841 // The base address should be the address we were loaded at. 842 ASSERT_EQ(info.dli_fbase, base_address); 843 844 ASSERT_EQ(0, dlclose(self)); 845} 846 847TEST(dlfcn, dlopen_executable_by_absolute_path) { 848 void* handle1 = dlopen(nullptr, RTLD_NOW); 849 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 850 851 void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW); 852 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 853 854#if defined(__BIONIC__) 855 ASSERT_EQ(handle1, handle2); 856#else 857 GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: " 858 "it loads a separate copy of the main executable " 859 "on dlopen by absolute path."; 860#endif 861} 862 863#if defined(__LP64__) 864#define PATH_TO_SYSTEM_LIB "/system/lib64/" 865#else 866#define PATH_TO_SYSTEM_LIB "/system/lib/" 867#endif 868#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so" 869 870TEST(dlfcn, dladdr_libc) { 871#if defined(__BIONIC__) 872 Dl_info info; 873 void* addr = reinterpret_cast<void*>(puts); // well-known libc function 874 ASSERT_TRUE(dladdr(addr, &info) != 0); 875 876 // /system/lib is symlink when this test is executed on host. 877 char libc_realpath[PATH_MAX]; 878 ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath); 879 880 ASSERT_STREQ(libc_realpath, info.dli_fname); 881 // TODO: add check for dfi_fbase 882 ASSERT_STREQ("puts", info.dli_sname); 883 ASSERT_EQ(addr, info.dli_saddr); 884#else 885 GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig " 886 "for libc.so, which is symlink itself (not a realpath).\n"; 887#endif 888} 889 890TEST(dlfcn, dladdr_invalid) { 891 Dl_info info; 892 893 dlerror(); // Clear any pending errors. 894 895 // No symbol corresponding to NULL. 896 ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success. 897 ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3). 898 899 // No symbol corresponding to a stack address. 900 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success. 901 ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3). 902} 903 904// GNU-style ELF hash tables are incompatible with the MIPS ABI. 905// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code. 906TEST(dlfcn, dlopen_library_with_only_gnu_hash) { 907#if !defined(__mips__) 908 dlerror(); // Clear any pending errors. 909 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW); 910 ASSERT_TRUE(handle != nullptr) << dlerror(); 911 auto guard = make_scope_guard([&]() { 912 dlclose(handle); 913 }); 914 void* sym = dlsym(handle, "getRandomNumber"); 915 ASSERT_TRUE(sym != nullptr) << dlerror(); 916 int (*fn)(void); 917 fn = reinterpret_cast<int (*)(void)>(sym); 918 EXPECT_EQ(4, fn()); 919 920 Dl_info dlinfo; 921 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo)); 922 923 ASSERT_TRUE(fn == dlinfo.dli_saddr); 924 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname); 925 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname); 926#else 927 GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n"; 928#endif 929} 930 931TEST(dlfcn, dlopen_library_with_only_sysv_hash) { 932 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW); 933 ASSERT_TRUE(handle != nullptr) << dlerror(); 934 auto guard = make_scope_guard([&]() { 935 dlclose(handle); 936 }); 937 void* sym = dlsym(handle, "getRandomNumber"); 938 ASSERT_TRUE(sym != nullptr) << dlerror(); 939 int (*fn)(void); 940 fn = reinterpret_cast<int (*)(void)>(sym); 941 EXPECT_EQ(4, fn()); 942 943 Dl_info dlinfo; 944 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo)); 945 946 ASSERT_TRUE(fn == dlinfo.dli_saddr); 947 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname); 948 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname); 949} 950 951TEST(dlfcn, dlopen_bad_flags) { 952 dlerror(); // Clear any pending errors. 953 void* handle; 954 955#if defined(__GLIBC__) 956 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags. 957 handle = dlopen(nullptr, 0); 958 ASSERT_TRUE(handle == nullptr); 959 ASSERT_SUBSTR("invalid", dlerror()); 960#endif 961 962 handle = dlopen(nullptr, 0xffffffff); 963 ASSERT_TRUE(handle == nullptr); 964 ASSERT_SUBSTR("invalid", dlerror()); 965 966 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we. 967 handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY); 968 ASSERT_TRUE(handle != nullptr); 969 ASSERT_SUBSTR(nullptr, dlerror()); 970} 971 972TEST(dlfcn, rtld_default_unknown_symbol) { 973 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME"); 974 ASSERT_TRUE(addr == nullptr); 975} 976 977TEST(dlfcn, rtld_default_known_symbol) { 978 void* addr = dlsym(RTLD_DEFAULT, "fopen"); 979 ASSERT_TRUE(addr != nullptr); 980} 981 982TEST(dlfcn, rtld_next_unknown_symbol) { 983 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME"); 984 ASSERT_TRUE(addr == nullptr); 985} 986 987TEST(dlfcn, rtld_next_known_symbol) { 988 void* addr = dlsym(RTLD_NEXT, "fopen"); 989 ASSERT_TRUE(addr != nullptr); 990} 991 992TEST(dlfcn, dlsym_weak_func) { 993 dlerror(); 994 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW); 995 ASSERT_TRUE(handle != nullptr); 996 997 int (*weak_func)(); 998 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func")); 999 ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror(); 1000 EXPECT_EQ(42, weak_func()); 1001 dlclose(handle); 1002} 1003 1004TEST(dlfcn, dlopen_undefined_weak_func) { 1005 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW); 1006 ASSERT_TRUE(handle != nullptr) << dlerror(); 1007 int (*weak_func)(); 1008 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func")); 1009 ASSERT_TRUE(weak_func != nullptr) << dlerror(); 1010 EXPECT_EQ(6551, weak_func()); 1011 dlclose(handle); 1012} 1013 1014TEST(dlfcn, dlopen_symlink) { 1015 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW); 1016 void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW); 1017 ASSERT_TRUE(handle1 != nullptr); 1018 ASSERT_TRUE(handle2 != nullptr); 1019 ASSERT_EQ(handle1, handle2); 1020 dlclose(handle1); 1021 dlclose(handle2); 1022} 1023 1024// libtest_dlopen_from_ctor_main.so depends on 1025// libtest_dlopen_from_ctor.so which has a constructor 1026// that calls dlopen(libc...). This is to test the situation 1027// described in b/7941716. 1028TEST(dlfcn, dlopen_dlopen_from_ctor) { 1029#if defined(__BIONIC__) 1030 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW); 1031 ASSERT_TRUE(handle != nullptr) << dlerror(); 1032 dlclose(handle); 1033#else 1034 GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n"; 1035#endif 1036} 1037 1038TEST(dlfcn, symbol_versioning_use_v1) { 1039 void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW); 1040 ASSERT_TRUE(handle != nullptr) << dlerror(); 1041 typedef int (*fn_t)(); 1042 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version")); 1043 ASSERT_TRUE(fn != nullptr) << dlerror(); 1044 ASSERT_EQ(1, fn()); 1045 dlclose(handle); 1046} 1047 1048TEST(dlfcn, symbol_versioning_use_v2) { 1049 void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW); 1050 ASSERT_TRUE(handle != nullptr) << dlerror(); 1051 typedef int (*fn_t)(); 1052 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version")); 1053 ASSERT_TRUE(fn != nullptr) << dlerror(); 1054 ASSERT_EQ(2, fn()); 1055 dlclose(handle); 1056} 1057 1058TEST(dlfcn, symbol_versioning_use_other_v2) { 1059 void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW); 1060 ASSERT_TRUE(handle != nullptr) << dlerror(); 1061 typedef int (*fn_t)(); 1062 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version")); 1063 ASSERT_TRUE(fn != nullptr) << dlerror(); 1064 ASSERT_EQ(20, fn()); 1065 dlclose(handle); 1066} 1067 1068TEST(dlfcn, symbol_versioning_use_other_v3) { 1069 void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW); 1070 ASSERT_TRUE(handle != nullptr) << dlerror(); 1071 typedef int (*fn_t)(); 1072 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version")); 1073 ASSERT_TRUE(fn != nullptr) << dlerror(); 1074 ASSERT_EQ(3, fn()); 1075 dlclose(handle); 1076} 1077 1078TEST(dlfcn, symbol_versioning_default_via_dlsym) { 1079 void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW); 1080 ASSERT_TRUE(handle != nullptr) << dlerror(); 1081 typedef int (*fn_t)(); 1082 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function")); 1083 ASSERT_TRUE(fn != nullptr) << dlerror(); 1084 ASSERT_EQ(3, fn()); // the default version is 3 1085 dlclose(handle); 1086} 1087 1088TEST(dlfcn, dlvsym_smoke) { 1089 void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW); 1090 ASSERT_TRUE(handle != nullptr) << dlerror(); 1091 typedef int (*fn_t)(); 1092 1093 { 1094 fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion")); 1095 ASSERT_TRUE(fn == nullptr); 1096 ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror()); 1097 } 1098 1099 { 1100 fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2")); 1101 ASSERT_TRUE(fn != nullptr) << dlerror(); 1102 ASSERT_EQ(2, fn()); 1103 } 1104 1105 dlclose(handle); 1106} 1107 1108// This preempts the implementation from libtest_versioned_lib.so 1109extern "C" int version_zero_function() { 1110 return 0; 1111} 1112 1113// This preempts the implementation from libtest_versioned_uselibv*.so 1114extern "C" int version_zero_function2() { 1115 return 0; 1116} 1117 1118TEST(dlfcn, dt_runpath_smoke) { 1119 void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW); 1120 ASSERT_TRUE(handle != nullptr) << dlerror(); 1121 1122 typedef void *(* dlopen_b_fn)(); 1123 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b"); 1124 ASSERT_TRUE(fn != nullptr) << dlerror(); 1125 1126 void *p = fn(); 1127 ASSERT_TRUE(p != nullptr); 1128 1129 dlclose(handle); 1130} 1131 1132TEST(dlfcn, dt_runpath_absolute_path) { 1133 void* handle = dlopen(PATH_TO_SYSTEM_LIB "libtest_dt_runpath_d.so", RTLD_NOW); 1134 ASSERT_TRUE(handle != nullptr) << dlerror(); 1135 1136 typedef void *(* dlopen_b_fn)(); 1137 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b"); 1138 ASSERT_TRUE(fn != nullptr) << dlerror(); 1139 1140 void *p = fn(); 1141 ASSERT_TRUE(p != nullptr); 1142 1143 dlclose(handle); 1144} 1145