dlfcn_test.cpp revision 279a22f96e639e76c801bdb39aee5576f2280fe0
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 "gtest_ex.h" 26#include "private/ScopeGuard.h" 27 28#include <string> 29 30#define ASSERT_SUBSTR(needle, haystack) \ 31 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) 32 33static bool g_called = false; 34extern "C" void DlSymTestFunction() { 35 g_called = true; 36} 37 38static int g_ctor_function_called = 0; 39 40extern "C" void ctor_function() __attribute__ ((constructor)); 41 42extern "C" void ctor_function() { 43 g_ctor_function_called = 17; 44} 45 46TEST(dlfcn, ctor_function_call) { 47 ASSERT_EQ(17, g_ctor_function_called); 48} 49 50TEST(dlfcn, dlsym_in_self) { 51 dlerror(); // Clear any pending errors. 52 void* self = dlopen(NULL, RTLD_NOW); 53 ASSERT_TRUE(self != NULL); 54 ASSERT_TRUE(dlerror() == NULL); 55 56 void* sym = dlsym(self, "DlSymTestFunction"); 57 ASSERT_TRUE(sym != NULL); 58 59 void (*function)() = reinterpret_cast<void(*)()>(sym); 60 61 g_called = false; 62 function(); 63 ASSERT_TRUE(g_called); 64 65 ASSERT_EQ(0, dlclose(self)); 66} 67 68TEST(dlfcn, dlsym_with_dependencies) { 69 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); 70 ASSERT_TRUE(handle != NULL); 71 dlerror(); 72 // This symbol is in DT_NEEDED library. 73 void* sym = dlsym(handle, "getRandomNumber"); 74 ASSERT_TRUE(sym != NULL); 75 int (*fn)(void); 76 fn = reinterpret_cast<int (*)(void)>(sym); 77 EXPECT_EQ(4, fn()); 78 dlclose(handle); 79} 80 81TEST(dlfcn, dlopen_noload) { 82 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD); 83 ASSERT_TRUE(handle == NULL); 84 handle = dlopen("libtest_simple.so", RTLD_NOW); 85 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD); 86 ASSERT_TRUE(handle != NULL); 87 ASSERT_TRUE(handle2 != NULL); 88 ASSERT_TRUE(handle == handle2); 89 ASSERT_EQ(0, dlclose(handle)); 90 ASSERT_EQ(0, dlclose(handle2)); 91} 92 93// ifuncs are only supported on intel and arm64 for now 94#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__) 95TEST(dlfcn, ifunc) { 96 typedef const char* (*fn_ptr)(); 97 98 // ifunc's choice depends on whether IFUNC_CHOICE has a value 99 // first check the set case 100 setenv("IFUNC_CHOICE", "set", 1); 101 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); 102 ASSERT_TRUE(handle != NULL); 103 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); 104 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); 105 ASSERT_TRUE(foo_ptr != NULL); 106 ASSERT_TRUE(foo_library_ptr != NULL); 107 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0); 108 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0); 109 dlclose(handle); 110 111 // then check the unset case 112 unsetenv("IFUNC_CHOICE"); 113 handle = dlopen("libtest_ifunc.so", RTLD_NOW); 114 ASSERT_TRUE(handle != NULL); 115 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); 116 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); 117 ASSERT_TRUE(foo_ptr != NULL); 118 ASSERT_TRUE(foo_library_ptr != NULL); 119 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); 120 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); 121 dlclose(handle); 122} 123 124TEST(dlfcn, ifunc_ctor_call) { 125 typedef const char* (*fn_ptr)(); 126 127 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); 128 ASSERT_TRUE(handle != nullptr) << dlerror(); 129 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative")); 130 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 131 ASSERT_STREQ("false", is_ctor_called()); 132 133 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot")); 134 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); 135 ASSERT_STREQ("true", is_ctor_called()); 136 dlclose(handle); 137} 138#endif 139 140TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { 141 // This is the structure of the test library and 142 // its dt_needed libraries 143 // libtest_relo_check_dt_needed_order.so 144 // | 145 // +-> libtest_relo_check_dt_needed_order_1.so 146 // | 147 // +-> libtest_relo_check_dt_needed_order_2.so 148 // 149 // The root library references relo_test_get_answer_lib - which is defined 150 // in both dt_needed libraries, the correct relocation should 151 // use the function defined in libtest_relo_check_dt_needed_order_1.so 152 void* handle = nullptr; 153 auto guard = make_scope_guard([&]() { 154 dlclose(handle); 155 }); 156 157 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW); 158 ASSERT_TRUE(handle != nullptr) << dlerror(); 159 160 typedef int (*fn_t) (void); 161 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer")); 162 ASSERT_TRUE(fn != nullptr) << dlerror(); 163 ASSERT_EQ(1, fn()); 164} 165 166TEST(dlfcn, dlopen_check_order_dlsym) { 167 // Here is how the test library and its dt_needed 168 // libraries are arranged 169 // 170 // libtest_check_order_children.so 171 // | 172 // +-> ..._1_left.so 173 // | | 174 // | +-> ..._a.so 175 // | | 176 // | +-> ...r_b.so 177 // | 178 // +-> ..._2_right.so 179 // | | 180 // | +-> ..._d.so 181 // | | 182 // | +-> ..._b.so 183 // | 184 // +-> ..._3_c.so 185 // 186 // load order should be (1, 2, 3, a, b, d) 187 // 188 // get_answer() is defined in (2, 3, a, b, c) 189 // get_answer2() is defined in (b, d) 190 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"); 191 ASSERT_TRUE(sym == nullptr); 192 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL); 193 ASSERT_TRUE(handle != nullptr) << dlerror(); 194 typedef int (*fn_t) (void); 195 fn_t fn, fn2; 196 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer")); 197 ASSERT_TRUE(fn != NULL) << dlerror(); 198 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2")); 199 ASSERT_TRUE(fn2 != NULL) << dlerror(); 200 201 ASSERT_EQ(42, fn()); 202 ASSERT_EQ(43, fn2()); 203 dlclose(handle); 204} 205 206TEST(dlfcn, dlopen_check_order_reloc_siblings) { 207 // This is how this one works: 208 // we lookup and call get_answer which is defined in '_2.so' 209 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so' 210 // the correct _impl() is implemented by '_a.so'; 211 // 212 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?) 213 // 214 // Here is the picture: 215 // 216 // libtest_check_order_reloc_siblings.so 217 // | 218 // +-> ..._1.so <- empty 219 // | | 220 // | +-> ..._a.so <- exports correct answer_impl() 221 // | | 222 // | +-> ..._b.so <- every other letter exporting incorrect one. 223 // | 224 // +-> ..._2.so <- empty 225 // | | 226 // | +-> ..._c.so 227 // | | 228 // | +-> ..._d.so 229 // | 230 // +-> ..._3.so <- empty 231 // | 232 // +-> ..._e.so 233 // | 234 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl(); 235 // implements incorrect get_answer_impl() 236 237 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 238 ASSERT_TRUE(handle == nullptr); 239#ifdef __BIONIC__ 240 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 241 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 242#endif 243 244 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 245 ASSERT_TRUE(handle != nullptr) << dlerror(); 246 247 typedef int (*fn_t) (void); 248 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer")); 249 ASSERT_TRUE(fn != nullptr) << dlerror(); 250 ASSERT_EQ(42, fn()); 251 252 ASSERT_EQ(0, dlclose(handle)); 253} 254 255TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) { 256 // This test uses the same library as dlopen_check_order_reloc_siblings. 257 // Unlike dlopen_check_order_reloc_siblings it preloads 258 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to 259 // dlopen(libtest_check_order_reloc_siblings.so) 260 261 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 262 ASSERT_TRUE(handle == nullptr); 263 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD); 264 ASSERT_TRUE(handle == nullptr); 265 266 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL); 267 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror(); 268 269 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 270 ASSERT_TRUE(handle != nullptr) << dlerror(); 271 272 ASSERT_EQ(0, dlclose(handle_for_1)); 273 274 typedef int (*fn_t) (void); 275 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer")); 276 ASSERT_TRUE(fn != nullptr) << dlerror(); 277 ASSERT_EQ(42, fn()); 278 279 ASSERT_EQ(0, dlclose(handle)); 280} 281 282TEST(dlfcn, dlopen_check_order_reloc_grandchild) { 283 // This is how this one works: 284 // we lookup and call grandchild_get_answer which is defined in '_2.so' 285 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so' 286 // the correct _impl() is implemented by '_c_1.so'; 287 // 288 // Here is the picture of subtree: 289 // 290 // libtest_check_order_reloc_siblings.so 291 // | 292 // +-> ..._2.so <- grandchild_get_answer() 293 // | 294 // +-> ..._c.so <- empty 295 // | | 296 // | +-> _c_1.so <- exports correct answer_impl() 297 // | | 298 // | +-> _c_2.so <- exports incorrect answer_impl() 299 // | 300 // +-> ..._d.so <- empty 301 302 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 303 ASSERT_TRUE(handle == nullptr); 304#ifdef __BIONIC__ 305 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 306 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 307#endif 308 309 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 310 ASSERT_TRUE(handle != nullptr) << dlerror(); 311 312 typedef int (*fn_t) (void); 313 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer")); 314 ASSERT_TRUE(fn != nullptr) << dlerror(); 315 ASSERT_EQ(42, fn()); 316 317 ASSERT_EQ(0, dlclose(handle)); 318} 319 320TEST(dlfcn, dlopen_check_order_reloc_nephew) { 321 // This is how this one works: 322 // we lookup and call nephew_get_answer which is defined in '_2.so' 323 // and in turn calls external get_answer_impl() defined in '_[a-f].so' 324 // the correct _impl() is implemented by '_a.so'; 325 // 326 // Here is the picture: 327 // 328 // libtest_check_order_reloc_siblings.so 329 // | 330 // +-> ..._1.so <- empty 331 // | | 332 // | +-> ..._a.so <- exports correct answer_impl() 333 // | | 334 // | +-> ..._b.so <- every other letter exporting incorrect one. 335 // | 336 // +-> ..._2.so <- empty 337 // | | 338 // | +-> ..._c.so 339 // | | 340 // | +-> ..._d.so 341 // | 342 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl(); 343 // | 344 // +-> ..._e.so 345 // | 346 // +-> ..._f.so 347 348 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD); 349 ASSERT_TRUE(handle == nullptr); 350#ifdef __BIONIC__ 351 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 352 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 353#endif 354 355 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL); 356 ASSERT_TRUE(handle != nullptr) << dlerror(); 357 358 typedef int (*fn_t) (void); 359 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer")); 360 ASSERT_TRUE(fn != nullptr) << dlerror(); 361 ASSERT_EQ(42, fn()); 362 363 ASSERT_EQ(0, dlclose(handle)); 364} 365 366TEST(dlfcn, check_unload_after_reloc) { 367 // This is how this one works: 368 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child 369 // | 370 // +-> libtest_two_parents_child 371 // 372 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child 373 // | 374 // +-> libtest_two_parents_child 375 // 376 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so 377 // as a second step it dlopens parent2 and dlcloses parent1... 378 379 test_isolated([] { 380 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL); 381 ASSERT_TRUE(handle != nullptr) << dlerror(); 382 383 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL); 384 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 385 386 typedef int (*fn_t) (void); 387 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer")); 388 ASSERT_TRUE(fn != nullptr) << dlerror(); 389 ASSERT_EQ(42, fn()); 390 391 ASSERT_EQ(0, dlclose(handle)); 392 393 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); 394 ASSERT_TRUE(handle != nullptr); 395 ASSERT_EQ(0, dlclose(handle)); 396 397 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer")); 398 ASSERT_TRUE(fn != nullptr) << dlerror(); 399 ASSERT_EQ(42, fn()); 400 401 ASSERT_EQ(0, dlclose(handle2)); 402 403 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); 404 ASSERT_TRUE(handle == nullptr); 405 }); 406} 407 408extern "C" int check_order_reloc_root_get_answer_impl() { 409 return 42; 410} 411 412TEST(dlfcn, dlopen_check_order_reloc_main_executable) { 413 // This is how this one works: 414 // we lookup and call get_answer3 which is defined in 'root.so' 415 // and in turn calls external root_get_answer_impl() defined in _2.so and 416 // above the correct _impl() is one in the executable. 417 // 418 // libtest_check_order_reloc_root.so 419 // | 420 // +-> ..._1.so <- empty 421 // | 422 // +-> ..._2.so <- gives incorrect answer for answer_main_impl() 423 // 424 425 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD); 426 ASSERT_TRUE(handle == nullptr); 427#ifdef __BIONIC__ 428 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 429 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 430#endif 431 432 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL); 433 ASSERT_TRUE(handle != nullptr) << dlerror(); 434 435 typedef int (*fn_t) (void); 436 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer")); 437 ASSERT_TRUE(fn != nullptr) << dlerror(); 438 ASSERT_EQ(42, fn()); 439 440 ASSERT_EQ(0, dlclose(handle)); 441} 442 443TEST(dlfcn, dlopen_check_rtld_local) { 444 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 445 ASSERT_TRUE(sym == nullptr); 446 447 // implicit RTLD_LOCAL 448 void* handle = dlopen("libtest_simple.so", RTLD_NOW); 449 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 450 ASSERT_TRUE(sym == nullptr); 451 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); 452 sym = dlsym(handle, "dlopen_testlib_simple_func"); 453 ASSERT_TRUE(sym != nullptr); 454 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 455 dlclose(handle); 456 457 // explicit RTLD_LOCAL 458 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL); 459 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 460 ASSERT_TRUE(sym == nullptr); 461 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror()); 462 sym = dlsym(handle, "dlopen_testlib_simple_func"); 463 ASSERT_TRUE(sym != nullptr); 464 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 465 dlclose(handle); 466} 467 468TEST(dlfcn, dlopen_check_rtld_global) { 469 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 470 ASSERT_TRUE(sym == nullptr); 471 472 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL); 473 ASSERT_TRUE(handle != nullptr) << dlerror(); 474 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 475 ASSERT_TRUE(sym != nullptr) << dlerror(); 476 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)()); 477 dlclose(handle); 478 479 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that 480 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); 481 ASSERT_EQ(sym, sym_after_dlclose); 482} 483 484// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> 485// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> 486// libtest_with_dependency_loop_a.so 487TEST(dlfcn, dlopen_check_loop) { 488 test_isolated([] { 489 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); 490 ASSERT_TRUE(handle != nullptr) << dlerror(); 491 void* f = dlsym(handle, "dlopen_test_loopy_function"); 492 ASSERT_TRUE(f != nullptr) << dlerror(); 493 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)()); 494 ASSERT_EQ(0, dlclose(handle)); 495 496 // dlopen second time to make sure that the library was unloaded correctly 497 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD); 498 ASSERT_TRUE(handle == nullptr); 499#ifdef __BIONIC__ 500 // TODO: glibc returns nullptr on dlerror() here. Is it bug? 501 ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 502#endif 503 504 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD); 505 ASSERT_TRUE(handle == nullptr); 506 }); 507} 508 509TEST(dlfcn, dlopen_nodelete) { 510 static bool is_unloaded = false; 511 512 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE); 513 ASSERT_TRUE(handle != nullptr) << dlerror(); 514 void (*set_unload_flag_ptr)(bool*); 515 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr")); 516 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 517 set_unload_flag_ptr(&is_unloaded); 518 519 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 520 ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); 521 ASSERT_EQ(1729U, *taxicab_number); 522 *taxicab_number = 2; 523 524 dlclose(handle); 525 ASSERT_TRUE(!is_unloaded); 526 527 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 528 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number); 529 ASSERT_EQ(2U, *taxicab_number_after_dlclose); 530 531 532 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW); 533 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number")); 534 ASSERT_EQ(taxicab_number2, taxicab_number); 535 536 ASSERT_EQ(2U, *taxicab_number2); 537 538 dlclose(handle); 539 ASSERT_TRUE(!is_unloaded); 540} 541 542TEST(dlfcn, dlopen_nodelete_on_second_dlopen) { 543 static bool is_unloaded = false; 544 545 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW); 546 ASSERT_TRUE(handle != nullptr) << dlerror(); 547 void (*set_unload_flag_ptr)(bool*); 548 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr")); 549 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 550 set_unload_flag_ptr(&is_unloaded); 551 552 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number")); 553 ASSERT_TRUE(taxicab_number != nullptr) << dlerror(); 554 555 ASSERT_EQ(1729U, *taxicab_number); 556 *taxicab_number = 2; 557 558 // This RTLD_NODELETE should be ignored 559 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE); 560 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 561 ASSERT_EQ(handle, handle1); 562 563 dlclose(handle1); 564 dlclose(handle); 565 566 ASSERT_TRUE(is_unloaded); 567} 568 569TEST(dlfcn, dlopen_nodelete_dt_flags_1) { 570 static bool is_unloaded = false; 571 572 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW); 573 ASSERT_TRUE(handle != nullptr) << dlerror(); 574 void (*set_unload_flag_ptr)(bool*); 575 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr")); 576 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror(); 577 set_unload_flag_ptr(&is_unloaded); 578 579 dlclose(handle); 580 ASSERT_TRUE(!is_unloaded); 581} 582 583TEST(dlfcn, dlsym_df_1_global) { 584#if !defined(__arm__) && !defined(__aarch64__) 585 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW); 586 ASSERT_TRUE(handle != nullptr) << dlerror(); 587 int (*get_answer)(); 588 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer")); 589 ASSERT_TRUE(get_answer != nullptr) << dlerror(); 590 ASSERT_EQ(42, get_answer()); 591 ASSERT_EQ(0, dlclose(handle)); 592#else 593 GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n"; 594#endif 595} 596 597TEST(dlfcn, dlopen_failure) { 598 void* self = dlopen("/does/not/exist", RTLD_NOW); 599 ASSERT_TRUE(self == NULL); 600#if defined(__BIONIC__) 601 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror()); 602#else 603 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror()); 604#endif 605} 606 607static void* ConcurrentDlErrorFn(void*) { 608 dlopen("/child/thread", RTLD_NOW); 609 return reinterpret_cast<void*>(strdup(dlerror())); 610} 611 612TEST(dlfcn, dlerror_concurrent) { 613 dlopen("/main/thread", RTLD_NOW); 614 const char* main_thread_error = dlerror(); 615 ASSERT_SUBSTR("/main/thread", main_thread_error); 616 617 pthread_t t; 618 ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL)); 619 void* result; 620 ASSERT_EQ(0, pthread_join(t, &result)); 621 char* child_thread_error = static_cast<char*>(result); 622 ASSERT_SUBSTR("/child/thread", child_thread_error); 623 free(child_thread_error); 624 625 ASSERT_SUBSTR("/main/thread", main_thread_error); 626} 627 628TEST(dlfcn, dlsym_failures) { 629 dlerror(); // Clear any pending errors. 630 void* self = dlopen(NULL, RTLD_NOW); 631 ASSERT_TRUE(self != NULL); 632 ASSERT_TRUE(dlerror() == NULL); 633 634 void* sym; 635 636#if defined(__BIONIC__) && !defined(__LP64__) 637 // RTLD_DEFAULT in lp32 bionic is not (void*)0 638 // so it can be distinguished from the NULL handle. 639 sym = dlsym(NULL, "test"); 640 ASSERT_TRUE(sym == NULL); 641 ASSERT_SUBSTR("dlsym library handle is null", dlerror()); 642#endif 643 644 // NULL symbol name. 645#if defined(__BIONIC__) 646 // glibc marks this parameter non-null and SEGVs if you cheat. 647 sym = dlsym(self, NULL); 648 ASSERT_TRUE(sym == NULL); 649 ASSERT_SUBSTR("", dlerror()); 650#endif 651 652 // Symbol that doesn't exist. 653 sym = dlsym(self, "ThisSymbolDoesNotExist"); 654 ASSERT_TRUE(sym == NULL); 655 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror()); 656 657 ASSERT_EQ(0, dlclose(self)); 658} 659 660TEST(dlfcn, dladdr) { 661 dlerror(); // Clear any pending errors. 662 void* self = dlopen(NULL, RTLD_NOW); 663 ASSERT_TRUE(self != NULL); 664 ASSERT_TRUE(dlerror() == NULL); 665 666 void* sym = dlsym(self, "DlSymTestFunction"); 667 ASSERT_TRUE(sym != NULL); 668 669 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address. 670 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2); 671 672 Dl_info info; 673 int rc = dladdr(addr, &info); 674 ASSERT_NE(rc, 0); // Zero on error, non-zero on success. 675 676 // Get the name of this executable. 677 char executable_path[PATH_MAX]; 678 rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path)); 679 ASSERT_NE(rc, -1); 680 executable_path[rc] = '\0'; 681 std::string executable_name(basename(executable_path)); 682 683 // The filename should be that of this executable. 684 // Note that we don't know whether or not we have the full path, so we want an "ends_with" test. 685 std::string dli_fname(info.dli_fname); 686 dli_fname = basename(&dli_fname[0]); 687 ASSERT_EQ(dli_fname, executable_name); 688 689 // The symbol name should be the symbol we looked up. 690 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); 691 692 // The address should be the exact address of the symbol. 693 ASSERT_EQ(info.dli_saddr, sym); 694 695 // Look in /proc/pid/maps to find out what address we were loaded at. 696 // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic. 697 void* base_address = NULL; 698 char line[BUFSIZ]; 699 FILE* fp = fopen("/proc/self/maps", "r"); 700 ASSERT_TRUE(fp != NULL); 701 while (fgets(line, sizeof(line), fp) != NULL) { 702 uintptr_t start = strtoul(line, 0, 16); 703 line[strlen(line) - 1] = '\0'; // Chomp the '\n'. 704 char* path = strchr(line, '/'); 705 if (path != NULL && strcmp(executable_path, path) == 0) { 706 base_address = reinterpret_cast<void*>(start); 707 break; 708 } 709 } 710 fclose(fp); 711 712 // The base address should be the address we were loaded at. 713 ASSERT_EQ(info.dli_fbase, base_address); 714 715 ASSERT_EQ(0, dlclose(self)); 716} 717 718TEST(dlfcn, dladdr_invalid) { 719 Dl_info info; 720 721 dlerror(); // Clear any pending errors. 722 723 // No symbol corresponding to NULL. 724 ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success. 725 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). 726 727 // No symbol corresponding to a stack address. 728 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success. 729 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). 730} 731 732// GNU-style ELF hash tables are incompatible with the MIPS ABI. 733// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code. 734TEST(dlfcn, dlopen_library_with_only_gnu_hash) { 735#if !defined(__mips__) 736 dlerror(); // Clear any pending errors. 737 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW); 738 ASSERT_TRUE(handle != nullptr) << dlerror(); 739 auto guard = make_scope_guard([&]() { 740 dlclose(handle); 741 }); 742 void* sym = dlsym(handle, "getRandomNumber"); 743 ASSERT_TRUE(sym != nullptr) << dlerror(); 744 int (*fn)(void); 745 fn = reinterpret_cast<int (*)(void)>(sym); 746 EXPECT_EQ(4, fn()); 747 748 Dl_info dlinfo; 749 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo)); 750 751 ASSERT_TRUE(fn == dlinfo.dli_saddr); 752 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname); 753 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname); 754#else 755 GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n"; 756#endif 757} 758 759TEST(dlfcn, dlopen_library_with_only_sysv_hash) { 760 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW); 761 ASSERT_TRUE(handle != nullptr) << dlerror(); 762 auto guard = make_scope_guard([&]() { 763 dlclose(handle); 764 }); 765 void* sym = dlsym(handle, "getRandomNumber"); 766 ASSERT_TRUE(sym != nullptr) << dlerror(); 767 int (*fn)(void); 768 fn = reinterpret_cast<int (*)(void)>(sym); 769 EXPECT_EQ(4, fn()); 770 771 Dl_info dlinfo; 772 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo)); 773 774 ASSERT_TRUE(fn == dlinfo.dli_saddr); 775 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname); 776 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname); 777} 778 779TEST(dlfcn, dlopen_bad_flags) { 780 dlerror(); // Clear any pending errors. 781 void* handle; 782 783#if defined(__GLIBC__) 784 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags. 785 handle = dlopen(NULL, 0); 786 ASSERT_TRUE(handle == NULL); 787 ASSERT_SUBSTR("invalid", dlerror()); 788#endif 789 790 handle = dlopen(NULL, 0xffffffff); 791 ASSERT_TRUE(handle == NULL); 792 ASSERT_SUBSTR("invalid", dlerror()); 793 794 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we. 795 handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY); 796 ASSERT_TRUE(handle != NULL); 797 ASSERT_SUBSTR(NULL, dlerror()); 798} 799 800TEST(dlfcn, rtld_default_unknown_symbol) { 801 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME"); 802 ASSERT_TRUE(addr == NULL); 803} 804 805TEST(dlfcn, rtld_default_known_symbol) { 806 void* addr = dlsym(RTLD_DEFAULT, "fopen"); 807 ASSERT_TRUE(addr != NULL); 808} 809 810TEST(dlfcn, rtld_next_unknown_symbol) { 811 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME"); 812 ASSERT_TRUE(addr == NULL); 813} 814 815TEST(dlfcn, rtld_next_known_symbol) { 816 void* addr = dlsym(RTLD_NEXT, "fopen"); 817 ASSERT_TRUE(addr != NULL); 818} 819 820TEST(dlfcn, dlsym_weak_func) { 821 dlerror(); 822 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW); 823 ASSERT_TRUE(handle != NULL); 824 825 int (*weak_func)(); 826 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func")); 827 ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror(); 828 EXPECT_EQ(42, weak_func()); 829 dlclose(handle); 830} 831 832TEST(dlfcn, dlopen_undefined_weak_func) { 833 test_isolated([] { 834 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW); 835 ASSERT_TRUE(handle != nullptr) << dlerror(); 836 int (*weak_func)(); 837 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func")); 838 ASSERT_TRUE(weak_func != nullptr) << dlerror(); 839 EXPECT_EQ(6551, weak_func()); 840 dlclose(handle); 841 }); 842} 843 844TEST(dlfcn, dlopen_symlink) { 845 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW); 846 void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW); 847 ASSERT_TRUE(handle1 != NULL); 848 ASSERT_TRUE(handle2 != NULL); 849 ASSERT_EQ(handle1, handle2); 850 dlclose(handle1); 851 dlclose(handle2); 852} 853 854// libtest_dlopen_from_ctor_main.so depends on 855// libtest_dlopen_from_ctor.so which has a constructor 856// that calls dlopen(libc...). This is to test the situation 857// described in b/7941716. 858TEST(dlfcn, dlopen_dlopen_from_ctor) { 859#if defined(__BIONIC__) 860 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW); 861 ASSERT_TRUE(handle != nullptr) << dlerror(); 862 dlclose(handle); 863#else 864 GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n"; 865#endif 866} 867