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
This commit is contained in:
parent
75f2dfca65
commit
697bd9fd38
|
@ -918,13 +918,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;
|
||||
|
@ -941,6 +945,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
|
||||
|
@ -978,31 +989,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) {
|
||||
|
|
|
@ -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<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 = 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<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);
|
||||
}
|
||||
|
||||
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) {
|
||||
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
|
||||
ASSERT_TRUE(handle != NULL);
|
||||
|
|
|
@ -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
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
Loading…
Reference in New Issue