From bc8587a6fe800c142ded3ee4598af888565060fd Mon Sep 17 00:00:00 2001 From: AlxcBTW <187763517+AlxcBTW@users.noreply.github.com> Date: Sat, 10 Oct 2026 04:25:25 +0200 Subject: [PATCH] fix(libc): end the process without detach routines in _Exit on Windows On Windows std::_Exit ends in ExitProcess, which still runs every module's DLL_PROCESS_DETACH and TLS callbacks after the other threads are gone. A static destructor that joins a worker then waits forever: a title that calls _Exit while libSceVideoOut's flip queue runs (ps5-opengl's retirement fail-stop) stays alive in FlipQueue's destructor. _Exit and libkernel's _exit now terminate the process with TerminateProcess, as _exit ends a POSIX process: no atexit handlers, stream flushes or module destructors. --- core/libs/prx/libc/include/Shutdown.hpp | 1 + core/libs/prx/libc/src/Process.cpp | 10 ++++++++++ core/libs/prx/libkernel/System/src/Process.cpp | 2 +- core/libs/tests/GuestSystemExit.cpp | 10 ++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libc/include/Shutdown.hpp b/core/libs/prx/libc/include/Shutdown.hpp index dc4007098..a7618a032 100644 --- a/core/libs/prx/libc/include/Shutdown.hpp +++ b/core/libs/prx/libc/include/Shutdown.hpp @@ -12,5 +12,6 @@ extern "C" void LibcRequestShutdown_nid_postfix(); extern "C" void LibcRequestExit_nid_postfix(int code); extern "C" [[noreturn]] void LibcAwaitExit_nid_postfix(); extern "C" [[noreturn]] void LibcExit_nid_no_patch(int code); +extern "C" [[noreturn]] void LibcTerminate_nid_no_patch(int code); #endif diff --git a/core/libs/prx/libc/src/Process.cpp b/core/libs/prx/libc/src/Process.cpp index 47140b365..ce307b378 100644 --- a/core/libs/prx/libc/src/Process.cpp +++ b/core/libs/prx/libc/src/Process.cpp @@ -8,6 +8,9 @@ #include #include #include +#ifdef _WIN32 +#include +#endif #include #include #include "prx/libc/include/Shutdown.hpp" @@ -106,6 +109,13 @@ extern "C" { std::fprintf(stderr, "[libc] _Exit(%d) called from %p\n", code, __builtin_return_address(0)); std::fflush(stderr); } + LibcTerminate_nid_no_patch(code); +} + +[[noreturn]] void LibcTerminate_nid_no_patch(int code) { +#ifdef _WIN32 + TerminateProcess(GetCurrentProcess(), static_cast(code)); +#endif std::_Exit(code); } diff --git a/core/libs/prx/libkernel/System/src/Process.cpp b/core/libs/prx/libkernel/System/src/Process.cpp index 647f75814..425306a72 100644 --- a/core/libs/prx/libkernel/System/src/Process.cpp +++ b/core/libs/prx/libkernel/System/src/Process.cpp @@ -208,7 +208,7 @@ void APS5_VABI exit_nid_postfix(int code) { } [[noreturn]] void APS5_VABI _exit_nid_postfix(int status) { - std::_Exit(status); + LibcTerminate_nid_no_patch(status); } int APS5_VABI system_nid_postfix(const char* command) { diff --git a/core/libs/tests/GuestSystemExit.cpp b/core/libs/tests/GuestSystemExit.cpp index 3a22d960f..6dc172ac0 100644 --- a/core/libs/tests/GuestSystemExit.cpp +++ b/core/libs/tests/GuestSystemExit.cpp @@ -5,6 +5,9 @@ #include #include #include +#ifdef _WIN32 +#include +#endif extern "C" int APS5_VABI sceSystemServiceLoadExec(const char*, const char* const*); extern "C" void APS5_VABI _Exit_nid_postfix(int); extern "C" void APS5_VABI catchReturnFromMain_nid_postfix(int); @@ -27,11 +30,18 @@ void APS5_VABI QuickFirst() { } void Require(bool value) { if (!value) std::abort(); } void UnexpectedCleanup() { std::_Exit(3); } +#ifdef _WIN32 +void WINAPI UnexpectedDetach(PVOID) { TerminateProcess(GetCurrentProcess(), 4); } +#endif } int main(int argc, char** argv) { if (argc > 1 && std::strcmp(argv[1], "--immediate") == 0) { LibcRegisterShutdown_nid_postfix(UnexpectedCleanup); Require(std::atexit(UnexpectedCleanup) == 0); +#ifdef _WIN32 + auto slot = FlsAlloc(UnexpectedDetach); + Require(slot != FLS_OUT_OF_INDEXES && FlsSetValue(slot, &slot)); +#endif _Exit_nid_postfix(0); return 2; }