Fix jump to unmapped memory on atexit

Split d-tor calls and soinfo_free to 2 separate steps

Bug: 18338888
Change-Id: Idbcb7242ade16fa18cba7fe30505ebd8d6023622
This commit is contained in:
Dmitriy Ivanov 2014-11-18 12:03:09 -08:00
parent 8eda0a6d69
commit a2547055f2
2 changed files with 35 additions and 7 deletions

View File

@ -1135,28 +1135,27 @@ static soinfo* find_library(const char* name, int rtld_flags, const android_dlex
return si;
}
static void soinfo_unload(soinfo* si) {
static void soinfo_unload_schedule(soinfo::soinfo_list_t& unload_list, soinfo* si) {
if (!si->can_unload()) {
TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name);
return;
}
if (si->ref_count == 1) {
TRACE("unloading '%s'", si->name);
si->call_destructors();
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);
soinfo_unload(child);
soinfo_unload_schedule(unload_list, child);
}
} else {
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);
if (needed != nullptr) {
soinfo_unload(needed);
soinfo_unload_schedule(unload_list, needed);
} else {
// Not found: for example if symlink was deleted between dlopen and dlclose
// Since we cannot really handle errors at this point - print and continue.
@ -1165,15 +1164,28 @@ static void soinfo_unload(soinfo* si) {
});
}
notify_gdb_of_unload(si);
si->ref_count = 0;
soinfo_free(si);
} else {
si->ref_count--;
TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count);
}
}
static void soinfo_unload(soinfo* root) {
soinfo::soinfo_list_t unload_list;
soinfo_unload_schedule(unload_list, root);
unload_list.for_each([](soinfo* si) {
si->call_destructors();
});
soinfo* si = nullptr;
while ((si = unload_list.pop_front()) != nullptr) {
TRACE("unloading '%s'", si->name);
notify_gdb_of_unload(si);
soinfo_free(si);
}
}
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
// Use basic string manipulation calls to avoid snprintf.
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.

View File

@ -19,3 +19,19 @@ extern "C" int check_order_reloc_get_answer_impl();
extern "C" int check_order_reloc_nephew_get_answer() {
return check_order_reloc_get_answer_impl();
}
namespace {
// The d-tor for this class is called on dlclose() -> __on_dlclose() -> __cxa_finalize()
// We use it to detect calls to prematurely unmapped libraries during dlclose.
// See also b/18338888
class CallNephewInDtor {
public:
~CallNephewInDtor() {
check_order_reloc_get_answer_impl();
}
} instance;
};
extern "C" void* get_instance() {
return &instance;
}