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.
This commit is contained in:
AlxcBTW 2026-10-10 04:25:25 +02:00 committed by Dean Galvin
parent f6af6d11d3
commit bc8587a6fe
4 changed files with 22 additions and 1 deletions

View File

@ -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

View File

@ -8,6 +8,9 @@
#include <mutex>
#include <thread>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#endif
#include <atomic>
#include <stdexcept>
#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<UINT>(code));
#endif
std::_Exit(code);
}

View File

@ -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) {

View File

@ -5,6 +5,9 @@
#include <cstdlib>
#include <stdexcept>
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#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;
}