mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibC+LibELF: Correctly call destructors on exit()
We currently don't call any DT_FINI_ARRAY functions, so change that. The call to `_fini` in `exit` is unnecessary, as we now call the function referenced by DT_FINI in `__call_fini_functions`.
This commit is contained in:
parent
dcff48356f
commit
0bff1f61b6
Notes:
sideshowbarker
2024-07-17 06:35:23 +09:00
Author: https://github.com/spholz Commit: https://github.com/SerenityOS/serenity/commit/0bff1f61b6 Pull-request: https://github.com/SerenityOS/serenity/pull/21203 Reviewed-by: https://github.com/BertalanD
5 changed files with 58 additions and 9 deletions
|
@ -345,6 +345,8 @@ static T c_str_to_floating_point(char const* str, char** endptr)
|
|||
|
||||
extern "C" {
|
||||
|
||||
void (*__call_fini_functions)();
|
||||
|
||||
void exit(int status)
|
||||
{
|
||||
__cxa_finalize(nullptr);
|
||||
|
@ -352,8 +354,7 @@ void exit(int status)
|
|||
if (secure_getenv("LIBC_DUMP_MALLOC_STATS"))
|
||||
serenity_dump_malloc_stats();
|
||||
|
||||
extern void _fini();
|
||||
_fini();
|
||||
__call_fini_functions();
|
||||
fflush(nullptr);
|
||||
|
||||
#ifndef _DYNAMIC_LOADER
|
||||
|
|
|
@ -38,12 +38,16 @@ namespace ELF {
|
|||
|
||||
static HashMap<DeprecatedString, NonnullRefPtr<ELF::DynamicLoader>> s_loaders;
|
||||
static DeprecatedString s_main_program_path;
|
||||
|
||||
// Dependencies have to always be added after the object that depends on them in `s_global_objects`.
|
||||
// This is needed for calling the destructors in the correct order.
|
||||
static OrderedHashMap<DeprecatedString, NonnullRefPtr<ELF::DynamicObject>> s_global_objects;
|
||||
|
||||
using EntryPointFunction = int (*)(int, char**, char**);
|
||||
using LibCExitFunction = void (*)(int);
|
||||
using DlIteratePhdrCallbackFunction = int (*)(struct dl_phdr_info*, size_t, void*);
|
||||
using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*);
|
||||
using CallFiniFunctionsFunction = void (*)();
|
||||
|
||||
extern "C" [[noreturn]] void _invoke_entry(int argc, char** argv, char** envp, EntryPointFunction entry);
|
||||
|
||||
|
@ -65,6 +69,7 @@ static Result<void, DlErrorMessage> __dlclose(void* handle);
|
|||
static Result<void*, DlErrorMessage> __dlopen(char const* filename, int flags);
|
||||
static Result<void*, DlErrorMessage> __dlsym(void* handle, char const* symbol_name);
|
||||
static Result<void, DlErrorMessage> __dladdr(void const* addr, Dl_info* info);
|
||||
static void __call_fini_functions();
|
||||
|
||||
Optional<DynamicObject::SymbolLookupResult> DynamicLinker::lookup_global_symbol(StringView name)
|
||||
{
|
||||
|
@ -305,6 +310,10 @@ static void initialize_libc(DynamicObject& libc)
|
|||
VERIFY(res.has_value());
|
||||
*((DlAddrFunction*)res.value().address.as_ptr()) = __dladdr;
|
||||
|
||||
res = libc.lookup_symbol("__call_fini_functions"sv);
|
||||
VERIFY(res.has_value());
|
||||
*((CallFiniFunctionsFunction*)res.value().address.as_ptr()) = __call_fini_functions;
|
||||
|
||||
res = libc.lookup_symbol("__libc_init"sv);
|
||||
VERIFY(res.has_value());
|
||||
typedef void libc_init_func();
|
||||
|
@ -384,11 +393,9 @@ static Result<void, DlErrorMessage> link_main_library(DeprecatedString const& pa
|
|||
|
||||
auto loaders = collect_loaders_for_library(path);
|
||||
|
||||
for (auto& loader : loaders) {
|
||||
auto dynamic_object = loader->map();
|
||||
if (dynamic_object)
|
||||
s_global_objects.set(dynamic_object->filepath(), *dynamic_object);
|
||||
}
|
||||
// Verify that all objects are already mapped
|
||||
for (auto& loader : loaders)
|
||||
VERIFY(!loader->map());
|
||||
|
||||
for (auto& loader : loaders) {
|
||||
bool success = loader->link(flags);
|
||||
|
@ -594,6 +601,36 @@ static Result<void, DlErrorMessage> __dladdr(void const* addr, Dl_info* info)
|
|||
return {};
|
||||
}
|
||||
|
||||
static void __call_fini_functions()
|
||||
{
|
||||
typedef void (*FiniFunc)();
|
||||
|
||||
for (auto& it : s_global_objects) {
|
||||
auto object = it.value;
|
||||
|
||||
if (object->has_fini_array_section()) {
|
||||
auto fini_array_section = object->fini_array_section();
|
||||
|
||||
FiniFunc* fini_begin = (FiniFunc*)(fini_array_section.address().as_ptr());
|
||||
FiniFunc* fini_end = fini_begin + fini_array_section.entry_count();
|
||||
while (fini_begin != fini_end) {
|
||||
--fini_end;
|
||||
|
||||
// Android sources claim that these can be -1, to be ignored.
|
||||
// 0 deffiniely shows up. Apparently 0/-1 are valid? Confusing.
|
||||
if (!*fini_end || ((FlatPtr)*fini_end == (FlatPtr)-1))
|
||||
continue;
|
||||
(*fini_end)();
|
||||
}
|
||||
}
|
||||
|
||||
if (object->has_fini_section()) {
|
||||
auto fini_function = object->fini_section_function();
|
||||
(fini_function)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_environment_variables()
|
||||
{
|
||||
for (char** env = s_envp; *env; ++env) {
|
||||
|
|
|
@ -803,7 +803,7 @@ void DynamicLoader::call_object_init_functions()
|
|||
typedef void (*InitFunc)();
|
||||
|
||||
if (m_dynamic_object->has_init_section()) {
|
||||
auto init_function = (InitFunc)(m_dynamic_object->init_section().address().as_ptr());
|
||||
auto init_function = m_dynamic_object->init_section_function();
|
||||
(init_function)();
|
||||
}
|
||||
|
||||
|
|
|
@ -377,6 +377,12 @@ DynamicObject::InitializationFunction DynamicObject::init_section_function() con
|
|||
return (InitializationFunction)init_section().address().as_ptr();
|
||||
}
|
||||
|
||||
DynamicObject::FinalizationFunction DynamicObject::fini_section_function() const
|
||||
{
|
||||
VERIFY(has_fini_section());
|
||||
return (FinalizationFunction)fini_section().address().as_ptr();
|
||||
}
|
||||
|
||||
char const* DynamicObject::name_for_dtag(ElfW(Sword) d_tag)
|
||||
{
|
||||
switch (d_tag) {
|
||||
|
|
|
@ -245,14 +245,19 @@ public:
|
|||
Symbol symbol(unsigned) const;
|
||||
|
||||
typedef void (*InitializationFunction)();
|
||||
typedef void (*FinalizationFunction)();
|
||||
typedef ElfW(Addr) (*IfuncResolver)();
|
||||
|
||||
bool has_init_section() const { return m_init_offset != 0; }
|
||||
bool has_init_array_section() const { return m_init_array_offset != 0; }
|
||||
Section init_section() const;
|
||||
InitializationFunction init_section_function() const;
|
||||
Section fini_section() const;
|
||||
Section init_array_section() const;
|
||||
|
||||
bool has_fini_section() const { return m_fini_offset != 0; }
|
||||
bool has_fini_array_section() const { return m_fini_array_offset != 0; }
|
||||
Section fini_section() const;
|
||||
FinalizationFunction fini_section_function() const;
|
||||
Section fini_array_section() const;
|
||||
|
||||
HashSection hash_section() const
|
||||
|
|
Loading…
Reference in a new issue