From 5ae82cba595d15e955aafb8da3fca9c5bcdeb551 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Tue, 2 Dec 2014 17:08:42 -0800 Subject: [PATCH] Fix soinfo_unload 1. Take into consideration that the local_group_root_ is not set for all of not linked libraries. 2. We need to check visited list earlier to avoid double soinfo_free. Change-Id: Iabc0a06a97c63f7e6bd4641731f50bb1466fed4f --- linker/linker.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index b2e746444..34099316f 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -320,7 +320,7 @@ static void soinfo_free(soinfo* si) { if (trav == nullptr) { // si was not in solist - DL_ERR("name \"%s\" is not in solist!", si->name); + DL_ERR("name \"%s\"@%p is not in solist!", si->name, si); return; } @@ -1150,20 +1150,29 @@ static void soinfo_unload(soinfo* root) { soinfo* si = nullptr; while ((si = depth_first_list.pop_front()) != nullptr) { + if (local_unload_list.contains(si)) { + continue; + } + local_unload_list.push_back(si); + if (si->has_min_version(0)) { soinfo* child = nullptr; while ((child = si->get_children().pop_front()) != nullptr) { - TRACE("%s needs to unload %s", si->name, child->name); + TRACE("%s@%p needs to unload %s@%p", si->name, si, child->name, child); if (local_unload_list.contains(child)) { continue; - } else if (child->get_local_group_root() != root) { + } else if (child->is_linked() && child->get_local_group_root() != root) { external_unload_list.push_back(child); } else { depth_first_list.push_front(child); } } } else { +#ifdef __LP64__ + __libc_fatal("soinfo for \"%s\"@%p has no version", si->name, si); +#else + PRINT("warning: soinfo for \"%s\"@%p has no version", si->name, si); for_each_dt_needed(si, [&] (const char* library_name) { TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); @@ -1175,7 +1184,7 @@ static void soinfo_unload(soinfo* root) { } else if (local_unload_list.contains(needed)) { // already visited return; - } else if (needed->get_local_group_root() != root) { + } else if (needed->is_linked() && needed->get_local_group_root() != root) { // external group external_unload_list.push_back(needed); } else { @@ -1183,6 +1192,7 @@ static void soinfo_unload(soinfo* root) { depth_first_list.push_front(needed); } }); +#endif } }