From 4bac6ea463a8f20793f5c1425965729ded1419fe Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 12 May 2015 11:12:27 -0700 Subject: [PATCH] Improved dlsym tests and fixes to linker Answers the question: what if dependent library was preloaded with RTLD_LOCAL flag. Also add test for RTLD_NEXT within local_group. Bug: http://b/17512583 Change-Id: I79e081e68b3a8c0ed8980d4275a06515fea94ec9 (cherry picked from commit 697bd9fd38ab078a117ad9a5777cf286c467b9b9) --- linker/linker.cpp | 47 ++++++------- tests/dlfcn_test.cpp | 67 +++++++++++++++++-- tests/libs/Android.mk | 19 +++++- tests/libs/dlsym_from_this_functions.cpp | 52 ++++++++++++++ ...om_this.cpp => dlsym_from_this_symbol.cpp} | 15 +---- tests/libs/dlsym_from_this_symbol2.cpp | 18 +++++ 6 files changed, 170 insertions(+), 48 deletions(-) create mode 100644 tests/libs/dlsym_from_this_functions.cpp rename tests/libs/{dlsym_from_this.cpp => dlsym_from_this_symbol.cpp} (60%) create mode 100644 tests/libs/dlsym_from_this_symbol2.cpp diff --git a/linker/linker.cpp b/linker/linker.cpp index c6decee64..64b6d4dbf 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -933,13 +933,17 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s } -// 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) { +static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until, + soinfo** found, SymbolName& symbol_name) { const ElfW(Sym)* result = nullptr; - SymbolName symbol_name(name); + bool skip_lookup = skip_until != nullptr; + + walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) { + if (skip_lookup) { + skip_lookup = current_soinfo != skip_until; + return true; + } - walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) { if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) { result = nullptr; return false; @@ -956,6 +960,13 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam return result; } +// 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) { + SymbolName symbol_name(name); + return dlsym_handle_lookup(si, nullptr, found, symbol_name); +} + /* This is used by dlsym(3) to performs a global symbol lookup. If the start value is null (for RTLD_DEFAULT), the search starts at the beginning of the global solist. Otherwise the search starts at the @@ -993,31 +1004,13 @@ const ElfW(Sym)* dlsym_linear_lookup(const char* name, } } - // If not found - look into local_group unless - // caller is part of the global group in which + // If not found - use dlsym_handle_lookup for caller's + // local_group unless it is part of the global group in which // case we already did it. if (s == nullptr && caller != nullptr && (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) { - soinfo* local_group_root = caller->get_local_group_root(); - - if (handle == RTLD_DEFAULT) { - start = local_group_root; - } - - for (soinfo* si = start; si != nullptr; si = si->next) { - if (si->get_local_group_root() != local_group_root) { - break; - } - - if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) { - return nullptr; - } - - if (s != nullptr) { - *found = si; - break; - } - } + return dlsym_handle_lookup(caller->get_local_group_root(), + (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name); } if (s != nullptr) { diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 6b1f10958..a5abda7b1 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -71,23 +71,80 @@ TEST(dlfcn, dlsym_from_sofile) { void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL); ASSERT_TRUE(handle != nullptr) << dlerror(); - // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT) + // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT) void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol"); ASSERT_TRUE(symbol == nullptr); ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror()); typedef int* (*fn_t)(); - fn_t fn = reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); + fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); + ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror(); - ASSERT_TRUE(fn != nullptr) << dlerror(); - - int* ptr = fn(); + int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT(); ASSERT_TRUE(ptr != nullptr) << dlerror(); ASSERT_EQ(42, *ptr); + fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT")); + ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror(); + + ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT(); + ASSERT_TRUE(ptr != nullptr) << dlerror(); + ASSERT_EQ(44, *ptr); + + fn_t lookup_dlsym_symbol_using_RTLD_NEXT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT")); + ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror(); + + ptr = lookup_dlsym_symbol_using_RTLD_NEXT(); + ASSERT_TRUE(ptr != nullptr) << dlerror(); + ASSERT_EQ(43, *ptr); + dlclose(handle); } +TEST(dlfcn, dlsym_from_sofile_with_preload) { + void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(preload != nullptr) << dlerror(); + + void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT) + void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol"); + ASSERT_TRUE(symbol == nullptr); + ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror()); + + typedef int* (*fn_t)(); + fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); + ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror(); + + int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT(); + ASSERT_TRUE(ptr != nullptr) << dlerror(); + ASSERT_EQ(42, *ptr); + + fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT")); + ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror(); + + ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT(); + ASSERT_TRUE(ptr != nullptr) << dlerror(); + ASSERT_EQ(44, *ptr); + + fn_t lookup_dlsym_symbol_using_RTLD_NEXT = + reinterpret_cast(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT")); + ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror(); + + ptr = lookup_dlsym_symbol_using_RTLD_NEXT(); + ASSERT_TRUE(ptr != nullptr) << dlerror(); + ASSERT_EQ(43, *ptr); + + dlclose(handle); + dlclose(preload); +} + TEST(dlfcn, dlsym_with_dependencies) { void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index c432c2e98..4e275ed4c 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -385,11 +385,26 @@ include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library to check RTLD_LOCAL with dlsym in 'this' # ----------------------------------------------------------------------------- -libtest_dlsym_from_this_src_files := dlsym_from_this.cpp +libtest_dlsym_from_this_src_files := dlsym_from_this_symbol.cpp + +libtest_dlsym_from_this_shared_libraries_target := libdl +libtest_dlsym_from_this_shared_libraries := libtest_dlsym_from_this_child module := libtest_dlsym_from_this -libtest_dlsym_from_this_shared_libraries_target := libdl +include $(LOCAL_PATH)/Android.build.testlib.mk +# ----------------------------------------------------------------------------- +libtest_dlsym_from_this_child_src_files := dlsym_from_this_functions.cpp + +libtest_dlsym_from_this_child_shared_libraries := libtest_dlsym_from_this_grandchild + +module := libtest_dlsym_from_this_child +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +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 # ----------------------------------------------------------------------------- diff --git a/tests/libs/dlsym_from_this_functions.cpp b/tests/libs/dlsym_from_this_functions.cpp new file mode 100644 index 000000000..1f357e01b --- /dev/null +++ b/tests/libs/dlsym_from_this_functions.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +extern int test_dlsym_symbol; + +int test_dlsym_symbol = -1; + +extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() { + dlerror(); + int* result = static_cast(dlsym(RTLD_DEFAULT, "test_dlsym_symbol")); + // TODO: remove this once b/20049306 is fixed + if (result == nullptr) { + printf("Cannot find the answer\n"); + } + return result; +} + +extern "C" int* lookup_dlsym_symbol2_using_RTLD_DEFAULT() { + dlerror(); + int* result = static_cast(dlsym(RTLD_DEFAULT, "test_dlsym_symbol2")); + // TODO: remove this once b/20049306 is fixed + if (result == nullptr) { + printf("Cannot find the answer\n"); + } + return result; +} + +extern "C" int* lookup_dlsym_symbol_using_RTLD_NEXT() { + dlerror(); + int* result = static_cast(dlsym(RTLD_NEXT, "test_dlsym_symbol")); + // TODO: remove this once b/20049306 is fixed + if (result == nullptr) { + printf("Cannot find the answer\n"); + } + return result; +} + diff --git a/tests/libs/dlsym_from_this.cpp b/tests/libs/dlsym_from_this_symbol.cpp similarity index 60% rename from tests/libs/dlsym_from_this.cpp rename to tests/libs/dlsym_from_this_symbol.cpp index b5215c941..c3ec255ca 100644 --- a/tests/libs/dlsym_from_this.cpp +++ b/tests/libs/dlsym_from_this_symbol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,18 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include int test_dlsym_symbol = 42; - -extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() { - dlerror(); - int* result = static_cast(dlsym(RTLD_DEFAULT, "test_dlsym_symbol")); - // TODO: remove this once b/20049306 is fixed - if (result == nullptr) { - printf("Cannot find the answer\n"); - } - return result; -} - diff --git a/tests/libs/dlsym_from_this_symbol2.cpp b/tests/libs/dlsym_from_this_symbol2.cpp new file mode 100644 index 000000000..20da1d576 --- /dev/null +++ b/tests/libs/dlsym_from_this_symbol2.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +int test_dlsym_symbol = 43; +int test_dlsym_symbol2 = 44;