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