Move dlsym and dladdr implementation to linker.cpp
Bug: http://b/25716705 Bug: http://b/22865643 Change-Id: If22fc1eda219f676b5fcc06490f7901d21d1749c
This commit is contained in:
parent
9d8632e1a7
commit
4a2c5aa30c
@ -16,12 +16,10 @@
|
|||||||
|
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <android/dlext.h>
|
|
||||||
#include <android/api-level.h>
|
#include <android/api-level.h>
|
||||||
|
|
||||||
#include <bionic/pthread_internal.h>
|
#include <bionic/pthread_internal.h>
|
||||||
@ -70,8 +68,7 @@ void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
|||||||
static void* dlopen_ext(const char* filename, int flags,
|
static void* dlopen_ext(const char* filename, int flags,
|
||||||
const android_dlextinfo* extinfo, void* caller_addr) {
|
const android_dlextinfo* extinfo, void* caller_addr) {
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
soinfo* caller = find_containing_library(caller_addr);
|
soinfo* result = do_dlopen(filename, flags, extinfo, caller_addr);
|
||||||
soinfo* result = do_dlopen(filename, flags, extinfo, caller);
|
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
|
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -92,71 +89,20 @@ void* dlopen(const char* filename, int flags) {
|
|||||||
extern android_namespace_t* g_anonymous_namespace;
|
extern android_namespace_t* g_anonymous_namespace;
|
||||||
|
|
||||||
void* dlsym(void* handle, const char* symbol) {
|
void* dlsym(void* handle, const char* symbol) {
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
|
||||||
|
|
||||||
// TODO(dimitry): move (most of) the code below to linker.cpp
|
|
||||||
#if !defined(__LP64__)
|
|
||||||
if (handle == nullptr) {
|
|
||||||
__bionic_format_dlerror("dlsym library handle is null", nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (symbol == nullptr) {
|
|
||||||
__bionic_format_dlerror("dlsym symbol name is null", nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
soinfo* found = nullptr;
|
|
||||||
const ElfW(Sym)* sym = nullptr;
|
|
||||||
void* caller_addr = __builtin_return_address(0);
|
void* caller_addr = __builtin_return_address(0);
|
||||||
soinfo* caller = find_containing_library(caller_addr);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
|
void* result;
|
||||||
|
if (!do_dlsym(handle, symbol, nullptr, caller_addr, &result)) {
|
||||||
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
__bionic_format_dlerror(linker_get_error_buffer(), nullptr);
|
||||||
sym = dlsym_linear_lookup(ns, symbol, &found, caller, handle);
|
|
||||||
} else {
|
|
||||||
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym != nullptr) {
|
|
||||||
unsigned bind = ELF_ST_BIND(sym->st_info);
|
|
||||||
|
|
||||||
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
|
|
||||||
return reinterpret_cast<void*>(found->resolve_symbol_address(sym));
|
|
||||||
}
|
|
||||||
|
|
||||||
__bionic_format_dlerror("symbol found but not global", symbol);
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
__bionic_format_dlerror("undefined symbol", symbol);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dladdr(const void* addr, Dl_info* info) {
|
int dladdr(const void* addr, Dl_info* info) {
|
||||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
|
return do_dladdr(addr, info);
|
||||||
// Determine if this address can be found in any library currently mapped.
|
|
||||||
soinfo* si = find_containing_library(addr);
|
|
||||||
if (si == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(info, 0, sizeof(Dl_info));
|
|
||||||
|
|
||||||
info->dli_fname = si->get_realpath();
|
|
||||||
// Address at which the shared object is loaded.
|
|
||||||
info->dli_fbase = reinterpret_cast<void*>(si->base);
|
|
||||||
|
|
||||||
// Determine if any symbol in the library contains the specified address.
|
|
||||||
ElfW(Sym)* sym = si->find_symbol_by_address(addr);
|
|
||||||
if (sym != nullptr) {
|
|
||||||
info->dli_sname = si->get_string(sym->st_name);
|
|
||||||
info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dlclose(void* handle) {
|
int dlclose(void* handle) {
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <android/api-level.h>
|
#include <android/api-level.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -891,20 +890,23 @@ soinfo::soinfo(android_namespace_t* ns, const char* realpath,
|
|||||||
this->namespace_ = ns;
|
this->namespace_ = ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t calculate_elf_hash(const char* name) {
|
||||||
|
const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
|
||||||
|
uint32_t h = 0, g;
|
||||||
|
|
||||||
|
while (*name_bytes) {
|
||||||
|
h = (h << 4) + *name_bytes++;
|
||||||
|
g = h & 0xf0000000;
|
||||||
|
h ^= g;
|
||||||
|
h ^= g >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t SymbolName::elf_hash() {
|
uint32_t SymbolName::elf_hash() {
|
||||||
if (!has_elf_hash_) {
|
if (!has_elf_hash_) {
|
||||||
const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
|
elf_hash_ = calculate_elf_hash(name_);
|
||||||
uint32_t h = 0, g;
|
|
||||||
|
|
||||||
while (*name) {
|
|
||||||
h = (h << 4) + *name++;
|
|
||||||
g = h & 0xf0000000;
|
|
||||||
h ^= g;
|
|
||||||
h ^= g >> 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
elf_hash_ = h;
|
|
||||||
has_elf_hash_ = true;
|
has_elf_hash_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,7 +1245,8 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
|
|||||||
|
|
||||||
|
|
||||||
static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
||||||
soinfo** found, SymbolName& symbol_name) {
|
soinfo** found, SymbolName& symbol_name,
|
||||||
|
const version_info* vi) {
|
||||||
const ElfW(Sym)* result = nullptr;
|
const ElfW(Sym)* result = nullptr;
|
||||||
bool skip_lookup = skip_until != nullptr;
|
bool skip_lookup = skip_until != nullptr;
|
||||||
|
|
||||||
@ -1253,7 +1256,7 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
|
if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
|
||||||
result = nullptr;
|
result = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1269,9 +1272,17 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
||||||
|
const char* name,
|
||||||
|
const version_info* vi,
|
||||||
|
soinfo** found,
|
||||||
|
soinfo* caller,
|
||||||
|
void* handle);
|
||||||
|
|
||||||
// This is used by dlsym(3). It performs symbol lookup only within the
|
// This is used by dlsym(3). It performs symbol lookup only within the
|
||||||
// specified soinfo object and its dependencies in breadth first order.
|
// 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* si, soinfo** found,
|
||||||
|
const char* name, const version_info* vi) {
|
||||||
// According to man dlopen(3) and posix docs in the case when si is handle
|
// 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
|
// 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.
|
// dependencies but also in all libraries loaded with RTLD_GLOBAL.
|
||||||
@ -1280,11 +1291,11 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam
|
|||||||
// libraries and they are loaded in breath-first (correct) order we can just execute
|
// libraries and they are loaded in breath-first (correct) order we can just execute
|
||||||
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
|
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
|
||||||
if (si == somain) {
|
if (si == somain) {
|
||||||
return dlsym_linear_lookup(&g_default_namespace, name, found, nullptr, RTLD_DEFAULT);
|
return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
return dlsym_handle_lookup(si, nullptr, found, symbol_name);
|
return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used by dlsym(3) to performs a global symbol lookup. If the
|
/* This is used by dlsym(3) to performs a global symbol lookup. If the
|
||||||
@ -1292,11 +1303,12 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam
|
|||||||
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).
|
||||||
*/
|
*/
|
||||||
const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
||||||
const char* name,
|
const char* name,
|
||||||
soinfo** found,
|
const version_info* vi,
|
||||||
soinfo* caller,
|
soinfo** found,
|
||||||
void* handle) {
|
soinfo* caller,
|
||||||
|
void* handle) {
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
|
|
||||||
soinfo::soinfo_list_t& soinfo_list = ns->soinfo_list();
|
soinfo::soinfo_list_t& soinfo_list = ns->soinfo_list();
|
||||||
@ -1322,7 +1334,7 @@ const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
|
if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1338,7 +1350,7 @@ const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|||||||
if (s == nullptr && caller != nullptr &&
|
if (s == nullptr && caller != nullptr &&
|
||||||
(caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
|
(caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
|
||||||
return dlsym_handle_lookup(caller->get_local_group_root(),
|
return dlsym_handle_lookup(caller->get_local_group_root(),
|
||||||
(handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
|
(handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != nullptr) {
|
if (s != nullptr) {
|
||||||
@ -2176,6 +2188,14 @@ static void soinfo_unload(soinfo* root) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
|
||||||
|
if (sym_ver == nullptr) {
|
||||||
|
return sym_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(sym_name) + "@" + sym_ver;
|
||||||
|
}
|
||||||
|
|
||||||
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
|
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
|
||||||
// Use basic string manipulation calls to avoid snprintf.
|
// Use basic string manipulation calls to avoid snprintf.
|
||||||
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
|
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
|
||||||
@ -2203,7 +2223,10 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
|||||||
parse_LD_LIBRARY_PATH(ld_library_path);
|
parse_LD_LIBRARY_PATH(ld_library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, soinfo *caller) {
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
||||||
|
void* caller_addr) {
|
||||||
|
soinfo* const caller = find_containing_library(caller_addr);
|
||||||
|
|
||||||
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
|
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
|
||||||
DL_ERR("invalid flags to dlopen: %x", flags);
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -2249,6 +2272,79 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
|||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int do_dladdr(const void* addr, Dl_info* info) {
|
||||||
|
// Determine if this address can be found in any library currently mapped.
|
||||||
|
soinfo* si = find_containing_library(addr);
|
||||||
|
if (si == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(Dl_info));
|
||||||
|
|
||||||
|
info->dli_fname = si->get_realpath();
|
||||||
|
// Address at which the shared object is loaded.
|
||||||
|
info->dli_fbase = reinterpret_cast<void*>(si->base);
|
||||||
|
|
||||||
|
// Determine if any symbol in the library contains the specified address.
|
||||||
|
ElfW(Sym)* sym = si->find_symbol_by_address(addr);
|
||||||
|
if (sym != nullptr) {
|
||||||
|
info->dli_sname = si->get_string(sym->st_name);
|
||||||
|
info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
|
||||||
|
void* caller_addr, void** symbol) {
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
if (handle == nullptr) {
|
||||||
|
DL_ERR("dlsym failed: library handle is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sym_name == nullptr) {
|
||||||
|
DL_ERR("dlsym failed: symbol name is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
soinfo* found = nullptr;
|
||||||
|
const ElfW(Sym)* sym = nullptr;
|
||||||
|
soinfo* caller = find_containing_library(caller_addr);
|
||||||
|
android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
|
||||||
|
|
||||||
|
version_info vi_instance;
|
||||||
|
version_info* vi = nullptr;
|
||||||
|
|
||||||
|
if (sym_ver != nullptr) {
|
||||||
|
vi_instance.name = sym_name;
|
||||||
|
vi_instance.elf_hash = calculate_elf_hash(sym_name);
|
||||||
|
vi = &vi_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
||||||
|
sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
|
||||||
|
} else {
|
||||||
|
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, sym_name, vi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sym != nullptr) {
|
||||||
|
uint32_t bind = ELF_ST_BIND(sym->st_info);
|
||||||
|
|
||||||
|
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
|
||||||
|
*symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void do_dlclose(soinfo* si) {
|
void do_dlclose(soinfo* si) {
|
||||||
ProtectedDataGuard guard;
|
ProtectedDataGuard guard;
|
||||||
soinfo_unload(si);
|
soinfo_unload(si);
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#ifndef _LINKER_H_
|
#ifndef _LINKER_H_
|
||||||
#define _LINKER_H_
|
#define _LINKER_H_
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <android/dlext.h>
|
#include <android/dlext.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -135,7 +136,7 @@ class SymbolName {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct version_info {
|
struct version_info {
|
||||||
version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
|
constexpr version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
|
||||||
|
|
||||||
uint32_t elf_hash;
|
uint32_t elf_hash;
|
||||||
const char* name;
|
const char* name;
|
||||||
@ -422,17 +423,15 @@ soinfo* get_libdl_info();
|
|||||||
|
|
||||||
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
||||||
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
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 *caller);
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, void* caller_addr);
|
||||||
void do_dlclose(soinfo* si);
|
void do_dlclose(soinfo* si);
|
||||||
|
|
||||||
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
||||||
|
|
||||||
const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, const char* name, soinfo** found,
|
bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
|
||||||
soinfo* caller, void* handle);
|
void* caller_addr, void** symbol);
|
||||||
|
|
||||||
soinfo* find_containing_library(const void* addr);
|
int do_dladdr(const void* addr, Dl_info* info);
|
||||||
|
|
||||||
const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
|
|
||||||
|
|
||||||
void debuggerd_init();
|
void debuggerd_init();
|
||||||
extern "C" abort_msg_t* g_abort_message;
|
extern "C" abort_msg_t* g_abort_message;
|
||||||
|
@ -760,7 +760,7 @@ TEST(dlfcn, dlsym_failures) {
|
|||||||
// so it can be distinguished from the NULL handle.
|
// so it can be distinguished from the NULL handle.
|
||||||
sym = dlsym(nullptr, "test");
|
sym = dlsym(nullptr, "test");
|
||||||
ASSERT_TRUE(sym == nullptr);
|
ASSERT_TRUE(sym == nullptr);
|
||||||
ASSERT_SUBSTR("dlsym library handle is null", dlerror());
|
ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NULL symbol name.
|
// NULL symbol name.
|
||||||
@ -768,7 +768,7 @@ TEST(dlfcn, dlsym_failures) {
|
|||||||
// glibc marks this parameter non-null and SEGVs if you cheat.
|
// glibc marks this parameter non-null and SEGVs if you cheat.
|
||||||
sym = dlsym(self, nullptr);
|
sym = dlsym(self, nullptr);
|
||||||
ASSERT_TRUE(sym == nullptr);
|
ASSERT_TRUE(sym == nullptr);
|
||||||
ASSERT_SUBSTR("", dlerror());
|
ASSERT_STREQ("dlsym failed: symbol name is null", dlerror());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Symbol that doesn't exist.
|
// Symbol that doesn't exist.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user