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 #define ASSERT_SUBSTR(needle, haystack) \
     30     ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
     31 
     32 static bool g_called = false;
     33 extern "C" void DlSymTestFunction() {
     34   g_called = true;
     35 }
     36 
     37 static int g_ctor_function_called = 0;
     38 
     39 extern "C" void ctor_function() __attribute__ ((constructor));
     40 
     41 extern "C" void ctor_function() {
     42   g_ctor_function_called = 17;
     43 }
     44 
     45 TEST(dlfcn, ctor_function_call) {
     46   ASSERT_EQ(17, g_ctor_function_called);
     47 }
     48 
     49 TEST(dlfcn, dlsym_in_self) {
     50   dlerror(); // Clear any pending errors.
     51   void* self = dlopen(NULL, RTLD_NOW);
     52   ASSERT_TRUE(self != NULL);
     53   ASSERT_TRUE(dlerror() == NULL);
     54 
     55   void* sym = dlsym(self, "DlSymTestFunction");
     56   ASSERT_TRUE(sym != NULL);
     57 
     58   void (*function)() = reinterpret_cast<void(*)()>(sym);
     59 
     60   g_called = false;
     61   function();
     62   ASSERT_TRUE(g_called);
     63 
     64   ASSERT_EQ(0, dlclose(self));
     65 }
     66 
     67 TEST(dlfcn, dlsym_with_dependencies) {
     68   void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
     69   ASSERT_TRUE(handle != NULL);
     70   dlerror();
     71   // This symbol is in DT_NEEDED library.
     72   void* sym = dlsym(handle, "getRandomNumber");
     73   ASSERT_TRUE(sym != NULL);
     74   int (*fn)(void);
     75   fn = reinterpret_cast<int (*)(void)>(sym);
     76   EXPECT_EQ(4, fn());
     77   dlclose(handle);
     78 }
     79 
     80 TEST(dlfcn, dlopen_noload) {
     81   void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
     82   ASSERT_TRUE(handle == NULL);
     83   handle = dlopen("libtest_simple.so", RTLD_NOW);
     84   void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
     85   ASSERT_TRUE(handle != NULL);
     86   ASSERT_TRUE(handle2 != NULL);
     87   ASSERT_TRUE(handle == handle2);
     88   ASSERT_EQ(0, dlclose(handle));
     89   ASSERT_EQ(0, dlclose(handle2));
     90 }
     91 
     92 // ifuncs are only supported on intel and arm64 for now
     93 #if defined(__i386__) || defined(__x86_64__)
     94 TEST(dlfcn, ifunc) {
     95   typedef const char* (*fn_ptr)();
     96 
     97   // ifunc's choice depends on whether IFUNC_CHOICE has a value
     98   // first check the set case
     99   setenv("IFUNC_CHOICE", "set", 1);
    100   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
    101   ASSERT_TRUE(handle != NULL);
    102   fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
    103   fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
    104   ASSERT_TRUE(foo_ptr != NULL);
    105   ASSERT_TRUE(foo_library_ptr != NULL);
    106   ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
    107   ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
    108   dlclose(handle);
    109 
    110   // then check the unset case
    111   unsetenv("IFUNC_CHOICE");
    112   handle = dlopen("libtest_ifunc.so", RTLD_NOW);
    113   ASSERT_TRUE(handle != NULL);
    114   foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
    115   foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
    116   ASSERT_TRUE(foo_ptr != NULL);
    117   ASSERT_TRUE(foo_library_ptr != NULL);
    118   ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
    119   ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
    120   dlclose(handle);
    121 }
    122 
    123 TEST(dlfcn, ifunc_ctor_call) {
    124   typedef const char* (*fn_ptr)();
    125 
    126   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
    127   ASSERT_TRUE(handle != nullptr) << dlerror();
    128   fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
    129   ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
    130   ASSERT_STREQ("false", is_ctor_called());
    131 
    132   is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
    133   ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
    134   ASSERT_STREQ("true", is_ctor_called());
    135   dlclose(handle);
    136 }
    137 #endif
    138 
    139 TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
    140   // This is the structure of the test library and
    141   // its dt_needed libraries
    142   // libtest_relo_check_dt_needed_order.so
    143   // |
    144   // +-> libtest_relo_check_dt_needed_order_1.so
    145   // |
    146   // +-> libtest_relo_check_dt_needed_order_2.so
    147   //
    148   // The root library references relo_test_get_answer_lib - which is defined
    149   // in both dt_needed libraries, the correct relocation should
    150   // use the function defined in libtest_relo_check_dt_needed_order_1.so
    151   void* handle = nullptr;
    152   auto guard = make_scope_guard([&]() {
    153     dlclose(handle);
    154   });
    155 
    156   handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
    157   ASSERT_TRUE(handle != nullptr) << dlerror();
    158 
    159   typedef int (*fn_t) (void);
    160   fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
    161   ASSERT_TRUE(fn != nullptr) << dlerror();
    162   ASSERT_EQ(1, fn());
    163 }
    164 
    165 TEST(dlfcn, dlopen_check_order) {
    166   // Here is how the test library and its dt_needed
    167   // libraries are arranged
    168   //
    169   //  libtest_check_order.so
    170   //  |
    171   //  +-> libtest_check_order_1_left.so
    172   //  |   |
    173   //  |   +-> libtest_check_order_a.so
    174   //  |   |
    175   //  |   +-> libtest_check_order_b.so
    176   //  |
    177   //  +-> libtest_check_order_2_right.so
    178   //  |   |
    179   //  |   +-> libtest_check_order_d.so
    180   //  |       |
    181   //  |       +-> libtest_check_order_b.so
    182   //  |
    183   //  +-> libtest_check_order_3_c.so
    184   //
    185   //  load order should be (1, 2, 3, a, b, d)
    186   //
    187   // get_answer() is defined in (2, 3, a, b, c)
    188   // get_answer2() is defined in (b, d)
    189   void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer");
    190   ASSERT_TRUE(sym == nullptr);
    191   void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL);
    192   ASSERT_TRUE(handle != nullptr);
    193   typedef int (*fn_t) (void);
    194   fn_t fn, fn2;
    195   fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"));
    196   ASSERT_TRUE(fn != NULL) << dlerror();
    197   fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2"));
    198   ASSERT_TRUE(fn2 != NULL) << dlerror();
    199 
    200   ASSERT_EQ(42, fn());
    201   ASSERT_EQ(43, fn2());
    202   dlclose(handle);
    203 }
    204 
    205 // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
    206 // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
    207 // libtest_with_dependency_loop_a.so
    208 TEST(dlfcn, dlopen_check_loop) {
    209   void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
    210 #if defined(__BIONIC__)
    211   ASSERT_TRUE(handle == nullptr);
    212   ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror());
    213   // This symbol should never be exposed
    214   void* f = dlsym(RTLD_DEFAULT, "dlopen_test_invalid_function");
    215   ASSERT_TRUE(f == nullptr);
    216   ASSERT_SUBSTR("undefined symbol: dlopen_test_invalid_function", dlerror());
    217 
    218   // dlopen second time to make sure that the library wasn't loaded even though dlopen returned null.
    219   // This may happen if during cleanup the root library or one of the depended libs were not removed
    220   // from soinfo list.
    221   handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
    222   ASSERT_TRUE(handle == nullptr);
    223   ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
    224 #else // glibc allows recursive links
    225   ASSERT_TRUE(handle != nullptr);
    226   dlclose(handle);
    227 #endif
    228 }
    229 
    230 TEST(dlfcn, dlopen_failure) {
    231   void* self = dlopen("/does/not/exist", RTLD_NOW);
    232   ASSERT_TRUE(self == NULL);
    233 #if defined(__BIONIC__)
    234   ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
    235 #else
    236   ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
    237 #endif
    238 }
    239 
    240 static void* ConcurrentDlErrorFn(void*) {
    241   dlopen("/child/thread", RTLD_NOW);
    242   return reinterpret_cast<void*>(strdup(dlerror()));
    243 }
    244 
    245 TEST(dlfcn, dlerror_concurrent) {
    246   dlopen("/main/thread", RTLD_NOW);
    247   const char* main_thread_error = dlerror();
    248   ASSERT_SUBSTR("/main/thread", main_thread_error);
    249 
    250   pthread_t t;
    251   ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
    252   void* result;
    253   ASSERT_EQ(0, pthread_join(t, &result));
    254   char* child_thread_error = static_cast<char*>(result);
    255   ASSERT_SUBSTR("/child/thread", child_thread_error);
    256   free(child_thread_error);
    257 
    258   ASSERT_SUBSTR("/main/thread", main_thread_error);
    259 }
    260 
    261 TEST(dlfcn, dlsym_failures) {
    262   dlerror(); // Clear any pending errors.
    263   void* self = dlopen(NULL, RTLD_NOW);
    264   ASSERT_TRUE(self != NULL);
    265   ASSERT_TRUE(dlerror() == NULL);
    266 
    267   void* sym;
    268 
    269 #if defined(__BIONIC__) && !defined(__LP64__)
    270   // RTLD_DEFAULT in lp32 bionic is not (void*)0
    271   // so it can be distinguished from the NULL handle.
    272   sym = dlsym(NULL, "test");
    273   ASSERT_TRUE(sym == NULL);
    274   ASSERT_SUBSTR("dlsym library handle is null", dlerror());
    275 #endif
    276 
    277   // NULL symbol name.
    278 #if defined(__BIONIC__)
    279   // glibc marks this parameter non-null and SEGVs if you cheat.
    280   sym = dlsym(self, NULL);
    281   ASSERT_TRUE(sym == NULL);
    282   ASSERT_SUBSTR("", dlerror());
    283 #endif
    284 
    285   // Symbol that doesn't exist.
    286   sym = dlsym(self, "ThisSymbolDoesNotExist");
    287   ASSERT_TRUE(sym == NULL);
    288   ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
    289 
    290   ASSERT_EQ(0, dlclose(self));
    291 }
    292 
    293 TEST(dlfcn, dladdr) {
    294   dlerror(); // Clear any pending errors.
    295   void* self = dlopen(NULL, RTLD_NOW);
    296   ASSERT_TRUE(self != NULL);
    297   ASSERT_TRUE(dlerror() == NULL);
    298 
    299   void* sym = dlsym(self, "DlSymTestFunction");
    300   ASSERT_TRUE(sym != NULL);
    301 
    302   // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
    303   void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
    304 
    305   Dl_info info;
    306   int rc = dladdr(addr, &info);
    307   ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
    308 
    309   // Get the name of this executable.
    310   char executable_path[PATH_MAX];
    311   rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
    312   ASSERT_NE(rc, -1);
    313   executable_path[rc] = '\0';
    314   std::string executable_name(basename(executable_path));
    315 
    316   // The filename should be that of this executable.
    317   // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
    318   std::string dli_fname(info.dli_fname);
    319   dli_fname = basename(&dli_fname[0]);
    320   ASSERT_EQ(dli_fname, executable_name);
    321 
    322   // The symbol name should be the symbol we looked up.
    323   ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
    324 
    325   // The address should be the exact address of the symbol.
    326   ASSERT_EQ(info.dli_saddr, sym);
    327 
    328   // Look in /proc/pid/maps to find out what address we were loaded at.
    329   // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
    330   void* base_address = NULL;
    331   char line[BUFSIZ];
    332   FILE* fp = fopen("/proc/self/maps", "r");
    333   ASSERT_TRUE(fp != NULL);
    334   while (fgets(line, sizeof(line), fp) != NULL) {
    335     uintptr_t start = strtoul(line, 0, 16);
    336     line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
    337     char* path = strchr(line, '/');
    338     if (path != NULL && strcmp(executable_path, path) == 0) {
    339       base_address = reinterpret_cast<void*>(start);
    340       break;
    341     }
    342   }
    343   fclose(fp);
    344 
    345   // The base address should be the address we were loaded at.
    346   ASSERT_EQ(info.dli_fbase, base_address);
    347 
    348   ASSERT_EQ(0, dlclose(self));
    349 }
    350 
    351 TEST(dlfcn, dladdr_invalid) {
    352   Dl_info info;
    353 
    354   dlerror(); // Clear any pending errors.
    355 
    356   // No symbol corresponding to NULL.
    357   ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
    358   ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
    359 
    360   // No symbol corresponding to a stack address.
    361   ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
    362   ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
    363 }
    364 
    365 // Our dynamic linker doesn't support GNU hash tables.
    366 #if defined(__BIONIC__)
    367 // GNU-style ELF hash tables are incompatible with the MIPS ABI.
    368 // MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
    369 #if !defined(__mips__)
    370 TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
    371   dlerror(); // Clear any pending errors.
    372   void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
    373   ASSERT_TRUE(handle == NULL);
    374   ASSERT_STREQ("dlopen failed: empty/missing DT_HASH in \"no-elf-hash-table-library.so\" (built with --hash-style=gnu?)", dlerror());
    375 }
    376 #endif
    377 #endif
    378 
    379 TEST(dlfcn, dlopen_bad_flags) {
    380   dlerror(); // Clear any pending errors.
    381   void* handle;
    382 
    383 #if defined(__GLIBC__)
    384   // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
    385   handle = dlopen(NULL, 0);
    386   ASSERT_TRUE(handle == NULL);
    387   ASSERT_SUBSTR("invalid", dlerror());
    388 #endif
    389 
    390   handle = dlopen(NULL, 0xffffffff);
    391   ASSERT_TRUE(handle == NULL);
    392   ASSERT_SUBSTR("invalid", dlerror());
    393 
    394   // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
    395   handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
    396   ASSERT_TRUE(handle != NULL);
    397   ASSERT_SUBSTR(NULL, dlerror());
    398 }
    399 
    400 TEST(dlfcn, rtld_default_unknown_symbol) {
    401   void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
    402   ASSERT_TRUE(addr == NULL);
    403 }
    404 
    405 TEST(dlfcn, rtld_default_known_symbol) {
    406   void* addr = dlsym(RTLD_DEFAULT, "fopen");
    407   ASSERT_TRUE(addr != NULL);
    408 }
    409 
    410 TEST(dlfcn, rtld_next_unknown_symbol) {
    411   void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
    412   ASSERT_TRUE(addr == NULL);
    413 }
    414 
    415 TEST(dlfcn, rtld_next_known_symbol) {
    416   void* addr = dlsym(RTLD_NEXT, "fopen");
    417   ASSERT_TRUE(addr != NULL);
    418 }
    419 
    420 TEST(dlfcn, dlsym_weak_func) {
    421   dlerror();
    422   void* handle = dlopen("libtest_dlsym_weak_func.so",RTLD_NOW);
    423   ASSERT_TRUE(handle != NULL);
    424 
    425   int (*weak_func)();
    426   weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
    427   ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
    428   EXPECT_EQ(42, weak_func());
    429   dlclose(handle);
    430 }
    431 
    432 TEST(dlfcn, dlopen_symlink) {
    433   void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
    434   void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
    435   ASSERT_TRUE(handle1 != NULL);
    436   ASSERT_TRUE(handle2 != NULL);
    437   ASSERT_EQ(handle1, handle2);
    438 }
    439