From ed8437078642e263119c39402c589398b3f8885b Mon Sep 17 00:00:00 2001 From: nikosszzz <19nikospap@gmail.com> Date: Sat, 1 Aug 2026 13:45:40 +0300 Subject: [PATCH] fix(libc): run thread-local destructors Why: Thread-atexit registrations were discarded, leaving objects alive after their guest TLS storage was released. What: Store registrations per host thread and run them in LIFO order before pthread keys and guest TLS are destroyed. Why safe: Only callbacks registered on the exiting thread run, once, before existing teardown continues. --- src/kernel/pthread.cpp | 6 ++++++ src/libs/libC.cpp | 35 ++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/kernel/pthread.cpp b/src/kernel/pthread.cpp index 7cb980d..6b1c342 100644 --- a/src/kernel/pthread.cpp +++ b/src/kernel/pthread.cpp @@ -65,6 +65,10 @@ namespace Libs { +namespace LibcInternalExt { +void RunThreadAtexitDestructors(); +} // namespace LibcInternalExt + namespace LibKernel { LIB_NAME("libkernel", "libkernel"); @@ -3347,6 +3351,8 @@ int PthreadGetCurrentPriorityForKernel() { static void CleanupThread(void* arg) { auto* thread = static_cast(arg); + LibcInternalExt::RunThreadAtexitDestructors(); + auto thread_dtors = g_pthread_context->GetThreadDtors(); if (thread_dtors != nullptr) { diff --git a/src/libs/libC.cpp b/src/libs/libC.cpp index 25edfd2..0f8749d 100644 --- a/src/libs/libC.cpp +++ b/src/libs/libC.cpp @@ -633,6 +633,15 @@ LIB_VERSION("LibcInternalExt", 1, "LibcInternal", 1, 1); static uint64_t g_mspace_atomic_id_mask = 0; static uint64_t g_mstate_table[64] = {0}; +using thread_atexit_destructor_t = KYTY_SYSV_ABI void (*)(void*); + +struct ThreadAtexitDestructor { + thread_atexit_destructor_t destructor; + void* object; +}; + +static thread_local std::vector g_thread_atexit_destructors; + struct Info { uint64_t size; uint32_t unknown1; @@ -650,25 +659,29 @@ void KYTY_SYSV_ABI LibcHeapGetTraceInfo(Info* info) { info->mstate_table = g_mstate_table; } -uint64_t KYTY_SYSV_ABI LibcInternalExtUnknownQBS714Jr3g(uint64_t arg0, uint64_t arg1, uint64_t arg2, - uint64_t arg3, uint64_t arg4, - uint64_t arg5) { +int KYTY_SYSV_ABI LibcInternalExtCxaThreadAtexit(thread_atexit_destructor_t destructor, void* object, + void* /*module_id*/) { PRINT_NAME(); - LOGF("\t arg0 = 0x%016" PRIx64 "\n" - "\t arg1 = 0x%016" PRIx64 "\n" - "\t arg2 = 0x%016" PRIx64 "\n" - "\t arg3 = 0x%016" PRIx64 "\n" - "\t arg4 = 0x%016" PRIx64 "\n" - "\t arg5 = 0x%016" PRIx64 "\n", - arg0, arg1, arg2, arg3, arg4, arg5); + g_thread_atexit_destructors.push_back({destructor, object}); return 0; } +void RunThreadAtexitDestructors() { + while (!g_thread_atexit_destructors.empty()) { + auto destructor = g_thread_atexit_destructors.back(); + g_thread_atexit_destructors.pop_back(); + + if (destructor.destructor != nullptr) { + destructor.destructor(destructor.object); + } + } +} + LIB_DEFINE(InitLibcInternalExt_1) { LIB_FUNC("NWtTN10cJzE", LibcInternalExt::LibcHeapGetTraceInfo); - LIB_FUNC("qBS714-Jr3g", LibcInternalExt::LibcInternalExtUnknownQBS714Jr3g); + LIB_FUNC("qBS714-Jr3g", LibcInternalExt::LibcInternalExtCxaThreadAtexit); } } // namespace LibcInternalExt