Inject shim libs as if they were DT_NEEDED.
The previous separate approach had one flaw: If the shim lib requires
another lib that's already loaded, find_library_internal() would return
the previously loaded copy, but the later load action would fail as the
ELF reader map of the initial loading round was already discarded and
thus a new ElfReader instance for the soinfo instance was created, which
didn't know about the previous reading/loading state.
Change-Id: Ib224dbd35d114197097e3dee14a077cc9130fedb
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 9084e92..eb7692f 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1238,14 +1238,15 @@
// g_ld_all_shim_libs maintains the references to memory as it used
// in the soinfo structures and in the g_active_shim_libs list.
-static std::vector<std::string> g_ld_all_shim_libs;
+typedef std::pair<std::string, std::string> ShimDescriptor;
+static std::vector<ShimDescriptor> g_ld_all_shim_libs;
// g_active_shim_libs are all shim libs that are still eligible
// to be loaded. We must remove a shim lib from the list before
// we load the library to avoid recursive loops (load shim libA
// for libB where libA also links against libB).
-static linked_list_t<const std::string> g_active_shim_libs;
+static linked_list_t<const ShimDescriptor> g_active_shim_libs;
static void reset_g_active_shim_libs(void) {
g_active_shim_libs.clear();
@@ -1258,47 +1259,36 @@
g_ld_all_shim_libs.clear();
if (path != nullptr) {
// We have historically supported ':' as well as ' ' in LD_SHIM_LIBS.
- g_ld_all_shim_libs = android::base::Split(path, " :");
- std::remove_if(g_ld_all_shim_libs.begin(),
- g_ld_all_shim_libs.end(),
- [] (const std::string& s) { return s.empty(); });
+ for (const auto& pair : android::base::Split(path, " :")) {
+ size_t pos = pair.find('|');
+ if (pos > 0 && pos < pair.length() - 1) {
+ auto desc = std::pair<std::string, std::string>(pair.substr(0, pos), pair.substr(pos + 1));
+ g_ld_all_shim_libs.push_back(desc);
+ }
+ }
}
reset_g_active_shim_libs();
}
-static bool shim_lib_matches(const char *shim_lib, const char *realpath) {
- const char *sep = strchr(shim_lib, '|');
- return sep != nullptr && strncmp(realpath, shim_lib, sep - shim_lib) == 0;
-}
-
template<typename F>
-static void shim_libs_for_each(const char *const path, F action) {
+static void for_each_matching_shim(const char *const path, F action) {
if (path == nullptr) return;
INFO("Finding shim libs for \"%s\"\n", path);
- std::vector<const std::string *> matched;
+ std::vector<const ShimDescriptor *> matched;
- g_active_shim_libs.for_each([&](const std::string *a_pair) {
- const char *pair = a_pair->c_str();
- if (shim_lib_matches(pair, path)) {
+ g_active_shim_libs.for_each([&](const ShimDescriptor *a_pair) {
+ if (a_pair->first == path) {
matched.push_back(a_pair);
}
});
- g_active_shim_libs.remove_if([&](const std::string *a_pair) {
- const char *pair = a_pair->c_str();
- return shim_lib_matches(pair, path);
+ g_active_shim_libs.remove_if([&](const ShimDescriptor *a_pair) {
+ return a_pair->first == path;
});
for (const auto& one_pair : matched) {
- const char* const pair = one_pair->c_str();
- const char* sep = strchr(pair, '|');
- soinfo *child = find_library(&g_default_namespace, sep+1, RTLD_GLOBAL, nullptr, nullptr);
- if (child) {
- INFO("Using shim lib \"%s\"\n", sep+1);
- action(child);
- } else {
- PRINT("Shim lib \"%s\" can not be loaded, ignoring.", sep+1);
- }
+ INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path);
+ action(one_pair->second.c_str());
}
}
@@ -1310,7 +1300,7 @@
// walk_dependencies_tree returns false if walk was terminated
// by the action and true otherwise.
template<typename F>
-static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, bool do_shims, F action) {
+static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
SoinfoLinkedList visit_list;
SoinfoLinkedList visited;
@@ -1330,13 +1320,6 @@
visited.push_back(si);
- if (do_shims) {
- shim_libs_for_each(si->get_realpath(), [&](soinfo* child) {
- si->add_child(child);
- visit_list.push_back(child);
- });
- }
-
si->get_children().for_each([&](soinfo* child) {
visit_list.push_back(child);
});
@@ -1352,7 +1335,7 @@
const ElfW(Sym)* result = nullptr;
bool skip_lookup = skip_until != nullptr;
- walk_dependencies_tree(&root, 1, false, [&](soinfo* current_soinfo) {
+ walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
if (skip_lookup) {
skip_lookup = current_soinfo != skip_until;
return true;
@@ -1751,6 +1734,7 @@
action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
}
}
+ for_each_matching_shim(si->get_realpath(), action);
}
template<typename F>
@@ -1760,6 +1744,7 @@
action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
}
}
+ for_each_matching_shim(elf_reader.name(), action);
}
static bool load_library(android_namespace_t* ns,
@@ -2205,7 +2190,6 @@
walk_dependencies_tree(
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
(start_with != nullptr && add_as_children) ? 1 : soinfos_count,
- true,
[&] (soinfo* si) {
local_group.push_back(si);
return true;