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