diff --git a/linker/linker.cpp b/linker/linker.cpp index 764b5cc5f..02ee9c703 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -963,6 +963,17 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until, // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { + // According to man dlopen(3) and posix docs in the case when si is handle + // of the main executable we need to search not only in the executable and its + // dependencies but also in all libraries loaded with RTLD_GLOBAL. + // + // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared + // libraries and they are loaded in breath-first (correct) order we can just execute + // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup. + if (si == somain) { + return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT); + } + SymbolName symbol_name(name); return dlsym_handle_lookup(si, nullptr, found, symbol_name); } diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a5abda7b1..3c9b8e33a 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -145,13 +145,28 @@ TEST(dlfcn, dlsym_from_sofile_with_preload) { dlclose(preload); } +TEST(dlfcn, dlsym_handle_global_sym) { + // check that we do not look into global group + // when looking up symbol by handle + void* handle = dlopen("libtest_empty.so", RTLD_NOW); + dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL); + void* sym = dlsym(handle, "getRandomNumber"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror()); + + sym = dlsym(handle, "DlSymTestFunction"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror()); + dlclose(handle); +} + TEST(dlfcn, dlsym_with_dependencies) { void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); - ASSERT_TRUE(handle != NULL); + ASSERT_TRUE(handle != nullptr); dlerror(); // This symbol is in DT_NEEDED library. void* sym = dlsym(handle, "getRandomNumber"); - ASSERT_TRUE(sym != NULL); + ASSERT_TRUE(sym != nullptr) << dlerror(); int (*fn)(void); fn = reinterpret_cast(sym); EXPECT_EQ(4, fn()); @@ -583,6 +598,15 @@ TEST(dlfcn, dlopen_check_rtld_global) { // RTLD_GLOBAL implies RTLD_NODELETE, let's check that void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_EQ(sym, sym_after_dlclose); + + // Check if dlsym() for main program's handle searches RTLD_GLOBAL + // shared libraries after symbol was not found in the main executable + // and dependent libraries. + void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW); + sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr) << dlerror(); + + dlclose(handle_for_main_executable); } // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 15fa55c21..a5ef622c5 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -404,6 +404,14 @@ libtest_dlsym_from_this_grandchild_src_files := dlsym_from_this_symbol2.cpp module := libtest_dlsym_from_this_grandchild include $(LOCAL_PATH)/Android.build.testlib.mk +# ----------------------------------------------------------------------------- +# Empty library +# ----------------------------------------------------------------------------- +libtest_empty_src_files := empty.cpp + +module := libtest_empty +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Library with weak undefined function # -----------------------------------------------------------------------------