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:
parent
8eda0a6d69
commit
a2547055f2
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user