Look into local group on dlsym with RTLD_DEFAULT
Fix dlsym to look into local group when called with RTLD_DEFAULT and RTLD_NEXT. Bug: 17512583 Change-Id: I541354e89539c712af2ea4ec751e546913027084
This commit is contained in:
parent
ab7c79e22e
commit
76ac1acdac
@ -101,16 +101,11 @@ void* dlsym(void* handle, const char* symbol) {
|
|||||||
|
|
||||||
soinfo* found = nullptr;
|
soinfo* found = nullptr;
|
||||||
ElfW(Sym)* sym = nullptr;
|
ElfW(Sym)* sym = nullptr;
|
||||||
if (handle == RTLD_DEFAULT) {
|
void* caller_addr = __builtin_return_address(0);
|
||||||
sym = dlsym_linear_lookup(symbol, &found, nullptr);
|
soinfo* caller = find_containing_library(caller_addr);
|
||||||
} else if (handle == RTLD_NEXT) {
|
|
||||||
void* caller_addr = __builtin_return_address(0);
|
|
||||||
soinfo* si = find_containing_library(caller_addr);
|
|
||||||
|
|
||||||
sym = nullptr;
|
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
||||||
if (si && si->next) {
|
sym = dlsym_linear_lookup(symbol, &found, caller, handle);
|
||||||
sym = dlsym_linear_lookup(symbol, &found, si->next);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
||||||
}
|
}
|
||||||
|
@ -738,15 +738,21 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
|
|||||||
beginning of the global solist. Otherwise the search starts at the
|
beginning of the global solist. Otherwise the search starts at the
|
||||||
specified soinfo (for RTLD_NEXT).
|
specified soinfo (for RTLD_NEXT).
|
||||||
*/
|
*/
|
||||||
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
|
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle) {
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
|
|
||||||
if (start == nullptr) {
|
soinfo* start = solist;
|
||||||
start = solist;
|
|
||||||
|
if (handle == RTLD_NEXT) {
|
||||||
|
if (caller == nullptr || caller->next == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
start = caller->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfW(Sym)* s = nullptr;
|
ElfW(Sym)* s = nullptr;
|
||||||
for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
|
for (soinfo* si = start; si != nullptr; si = si->next) {
|
||||||
if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
|
if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -758,6 +764,30 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not found - look into local_group unless
|
||||||
|
// caller 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = si->find_symbol_by_name(symbol_name);
|
||||||
|
if (s != nullptr) {
|
||||||
|
*found = si;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s != nullptr) {
|
if (s != nullptr) {
|
||||||
TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
|
TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
|
||||||
name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
|
name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
|
||||||
|
@ -351,7 +351,7 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
|||||||
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
|
||||||
void do_dlclose(soinfo* si);
|
void do_dlclose(soinfo* si);
|
||||||
|
|
||||||
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
|
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
|
||||||
soinfo* find_containing_library(const void* addr);
|
soinfo* find_containing_library(const void* addr);
|
||||||
|
|
||||||
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
|
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
|
||||||
|
@ -46,7 +46,7 @@ TEST(dlfcn, ctor_function_call) {
|
|||||||
ASSERT_EQ(17, g_ctor_function_called);
|
ASSERT_EQ(17, g_ctor_function_called);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlfcn, dlsym_in_self) {
|
TEST(dlfcn, dlsym_in_executable) {
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
void* self = dlopen(NULL, RTLD_NOW);
|
void* self = dlopen(NULL, RTLD_NOW);
|
||||||
ASSERT_TRUE(self != NULL);
|
ASSERT_TRUE(self != NULL);
|
||||||
@ -64,6 +64,27 @@ TEST(dlfcn, dlsym_in_self) {
|
|||||||
ASSERT_EQ(0, dlclose(self));
|
ASSERT_EQ(0, dlclose(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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"));
|
||||||
|
|
||||||
|
ASSERT_TRUE(fn != nullptr) << dlerror();
|
||||||
|
|
||||||
|
int* ptr = fn();
|
||||||
|
ASSERT_TRUE(ptr != nullptr) << dlerror();
|
||||||
|
ASSERT_EQ(42, *ptr);
|
||||||
|
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(dlfcn, dlsym_with_dependencies) {
|
TEST(dlfcn, dlsym_with_dependencies) {
|
||||||
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
|
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
|
||||||
ASSERT_TRUE(handle != NULL);
|
ASSERT_TRUE(handle != NULL);
|
||||||
|
@ -370,6 +370,15 @@ libtest_dlsym_weak_func_src_files := \
|
|||||||
module := libtest_dlsym_weak_func
|
module := libtest_dlsym_weak_func
|
||||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
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
|
||||||
|
|
||||||
|
module := libtest_dlsym_from_this
|
||||||
|
|
||||||
|
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Library with weak undefined function
|
# Library with weak undefined function
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
30
tests/libs/dlsym_from_this.cpp
Normal file
30
tests/libs/dlsym_from_this.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user