diff options
author | Dmitriy Ivanov <dimitry@google.com> | 2014-11-18 12:03:09 -0800 |
---|---|---|
committer | Dmitriy Ivanov <dimitry@google.com> | 2014-11-18 13:16:27 -0800 |
commit | a2547055f25db614601ee8651f2e42ece01f7842 (patch) | |
tree | d6cab7ae30f844f01c8c34dffd6a009a4f6fa4b1 /linker/linker.cpp | |
parent | 8eda0a6d69fda865b576bc18311a3d79c84b42a1 (diff) | |
download | android_bionic-a2547055f25db614601ee8651f2e42ece01f7842.tar.gz android_bionic-a2547055f25db614601ee8651f2e42ece01f7842.tar.bz2 android_bionic-a2547055f25db614601ee8651f2e42ece01f7842.zip |
Fix jump to unmapped memory on atexit
Split d-tor calls and soinfo_free to 2 separate steps
Bug: 18338888
Change-Id: Idbcb7242ade16fa18cba7fe30505ebd8d6023622
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r-- | linker/linker.cpp | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index 11d7b94a4..1d68db5a3 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -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. |