Fix logic in loading dependencies crossing namespace boundaries
This change addresses multiple problems introduced by
02586a2a34e6acfccf359b94db840f422b6c0231
1. In the case of unsuccessful dlopen the failure guard is triggered
for two namespaces which leads to double unload.
2. In the case where load_tasks includes libraries from 3 and more
namespaces it results in incorrect linking of libraries shared between
second and third/forth and so on namespaces.
The root cause of these problems was recursive call to find_libraries.
It does not do what it is expected to do. It does not form new load_tasks
list and immediately jumps to linking local_group. Not only this skips
reference counting it also will include unlinked but accessible library
from third (and fourth and fifth) namespaces in invalid local group. The
best case scenario here is that for 3 or more namesapces this will
fail to link. The worse case scenario it will link the library
incorrectly with will lead to very hard to catch bugs.
This change removes recursive call and replaces it with explicit list of
local_groups which should be linked. It also revisits the way we do
reference counting - with this change the reference counts are updated after
after libraries are successfully loaded.
Also update soinfo_free to abort in case when linker tries to free same
soinfo for the second time - this makes linker behavior less undefined.
Test: bionic-unit-tests
Bug: http://b/69787209
Change-Id: Iea25ced181a98c6503cce6e2b832c91d697342d5
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 6f472b5..273c36c 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -41,6 +41,17 @@
#define FLAG_GNU_HASH 0x00000040 // uses gnu hash
#define FLAG_MAPPED_BY_CALLER 0x00000080 // the map is reserved by the caller
// and should not be unmapped
+#define FLAG_IMAGE_LINKED 0x00000100 // Is image linked - this is a guard on link_image.
+ // The difference between this flag and
+ // FLAG_LINKED is that FLAG_LINKED
+ // means is set when load_group is
+ // successfully loaded whereas this
+ // flag is set to avoid linking image
+ // when link_image called for the
+ // second time. This situation happens
+ // when load group is crossing
+ // namespace boundary twice and second
+ // local group depends on the same libraries.
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
#define SOINFO_VERSION 3
@@ -243,7 +254,7 @@
void set_main_executable();
void set_nodelete();
- void increment_ref_count();
+ size_t increment_ref_count();
size_t decrement_ref_count();
soinfo* get_local_group_root() const;
@@ -273,6 +284,9 @@
void* to_handle();
private:
+ bool is_image_linked() const;
+ void set_image_linked();
+
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* elf_addr_lookup(const void* addr);
bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;