diff options
-rw-r--r-- | linker/linker.cpp | 47 | ||||
-rw-r--r-- | tests/dlfcn_test.cpp | 65 | ||||
-rw-r--r-- | tests/libs/Android.mk | 19 | ||||
-rw-r--r-- | tests/libs/dlsym_from_this_functions.cpp | 52 | ||||
-rw-r--r-- | tests/libs/dlsym_from_this_symbol.cpp (renamed from tests/libs/dlsym_from_this.cpp) | 15 | ||||
-rw-r--r-- | tests/libs/dlsym_from_this_symbol2.cpp | 18 |
6 files changed, 169 insertions, 47 deletions
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,21 +71,78 @@ 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<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT")); + fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT = + reinterpret_cast<fn_t>(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 = 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<fn_t>(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<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT")); + ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror(); - int* ptr = fn(); + 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<fn_t>(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<fn_t>(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<fn_t>(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) { 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 -module := libtest_dlsym_from_this libtest_dlsym_from_this_shared_libraries_target := libdl +libtest_dlsym_from_this_shared_libraries := libtest_dlsym_from_this_child + +module := libtest_dlsym_from_this +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 <dlfcn.h> +#include <stdio.h> + +extern int test_dlsym_symbol; + +int test_dlsym_symbol = -1; + +extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() { + dlerror(); + int* result = static_cast<int*>(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<int*>(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<int*>(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 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 <dlfcn.h> -#include <stdio.h> int test_dlsym_symbol = 42; - -extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() { - dlerror(); - int* result = static_cast<int*>(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; |