fix(libc): run atexit handlers in one order with __cxa_atexit destructors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
This commit is contained in:
parent
0a8b1d32b1
commit
fe4a2cf7d8
|
|
@ -18,6 +18,8 @@
|
|||
#include "prx/libc/include/General.hpp"
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" int APS5_VABI __cxa_atexit_nid_postfix(void (APS5_VABI *func)(void*), void* arg, void* dsoHandle);
|
||||
|
||||
namespace {
|
||||
|
||||
std::mutex shutdownMutex;
|
||||
|
|
@ -31,17 +33,9 @@ std::stop_source shutdownSource;
|
|||
std::atomic<bool> exitRequested{false};
|
||||
std::atomic<bool> exitStarted{false};
|
||||
using GuestExitCallback = void (APS5_VABI*)();
|
||||
std::mutex exitCallbackMutex;
|
||||
std::vector<GuestExitCallback> exitCallbacks;
|
||||
|
||||
void runGuestExitCallback() {
|
||||
GuestExitCallback callback;
|
||||
{
|
||||
std::lock_guard lock(exitCallbackMutex);
|
||||
callback = exitCallbacks.back();
|
||||
exitCallbacks.pop_back();
|
||||
}
|
||||
callback();
|
||||
void APS5_VABI RunGuestExitCallback(void* callback) {
|
||||
reinterpret_cast<GuestExitCallback>(callback)();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -166,11 +160,7 @@ int* APS5_VABI __error_nid_postfix() {
|
|||
int APS5_VABI atexit_nid_postfix(GuestExitCallback func) {
|
||||
if (func == nullptr)
|
||||
return 0;
|
||||
std::lock_guard lock(exitCallbackMutex);
|
||||
exitCallbacks.push_back(func);
|
||||
const int result = std::atexit(runGuestExitCallback);
|
||||
if (result != 0) exitCallbacks.pop_back();
|
||||
return result;
|
||||
return __cxa_atexit_nid_postfix(RunGuestExitCallback, reinterpret_cast<void*>(func), nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
extern "C" int APS5_VABI __cxa_atexit_nid_postfix(void (APS5_VABI *func)(void*), void* arg, void* dsoHandle);
|
||||
extern "C" int APS5_VABI atexit_nid_postfix(void (APS5_VABI *func)());
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
@ -19,14 +20,16 @@ void APS5_VABI GuestHandler(void*) { Record('G'); }
|
|||
|
||||
void HostHandler() { Record('H'); }
|
||||
|
||||
bool GuestHandlersRunFirst() {
|
||||
void APS5_VABI AtexitHandler() { Record('A'); }
|
||||
|
||||
template <typename Setup>
|
||||
bool ExitOrder(Setup setup, const char* expected) {
|
||||
if (pipe(events) != 0) return false;
|
||||
const pid_t child = fork();
|
||||
if (child < 0) return false;
|
||||
if (child == 0) {
|
||||
close(events[0]);
|
||||
__cxa_atexit_nid_postfix(GuestHandler, nullptr, nullptr);
|
||||
std::atexit(HostHandler);
|
||||
setup();
|
||||
LibcExit_nid_no_patch(0);
|
||||
}
|
||||
close(events[1]);
|
||||
|
|
@ -39,15 +42,19 @@ bool GuestHandlersRunFirst() {
|
|||
}
|
||||
close(events[0]);
|
||||
int status = 0;
|
||||
return waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0 && length == 2 && order[0] == 'G' && order[1] == 'H';
|
||||
return waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0 && length == 2 && order[0] == expected[0] && order[1] == expected[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (!GuestHandlersRunFirst()) {
|
||||
if (!ExitOrder([] { __cxa_atexit_nid_postfix(GuestHandler, nullptr, nullptr); std::atexit(HostHandler); }, "GH")) {
|
||||
std::fputs("guest exit handlers must run before the host exit handlers\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
if (!ExitOrder([] { __cxa_atexit_nid_postfix(GuestHandler, nullptr, nullptr); atexit_nid_postfix(AtexitHandler); }, "AG")) {
|
||||
std::fputs("atexit and __cxa_atexit handlers must run in reverse order of registration\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue