diff --git a/core/libs/prx/libc/CMakeLists.txt b/core/libs/prx/libc/CMakeLists.txt index 575971f71..f63141384 100644 --- a/core/libs/prx/libc/CMakeLists.txt +++ b/core/libs/prx/libc/CMakeLists.txt @@ -242,8 +242,9 @@ if(BUILD_TESTING) add_test(NAME application_heap_replacement COMMAND application_heap_tests) add_test(NAME application_heap_invalid_metadata COMMAND application_heap_tests invalid) add_test(NAME application_heap_default COMMAND application_heap_tests default) + add_test(NAME application_heap_exit_order COMMAND application_heap_tests exit-order) if(WIN32) - set_tests_properties(application_heap_replacement application_heap_invalid_metadata application_heap_default + set_tests_properties(application_heap_replacement application_heap_invalid_metadata application_heap_default application_heap_exit_order PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() endif() diff --git a/core/libs/prx/libc/src/ApplicationHeap.cpp b/core/libs/prx/libc/src/ApplicationHeap.cpp index 3cd055106..b24c4fe64 100644 --- a/core/libs/prx/libc/src/ApplicationHeap.cpp +++ b/core/libs/prx/libc/src/ApplicationHeap.cpp @@ -95,11 +95,10 @@ void requireAlignment(std::size_t alignment) { } void finalize() { - Initialize finalizeCallback; + Initialize finalizeCallback = nullptr; { std::lock_guard lock(heapMutex); - if (heapFailure) std::rethrow_exception(heapFailure); - if (heapFinalized) throw std::runtime_error("application heap: duplicate finalization"); + if (heapFinalized || heapFailure) return; finalizeCallback = heapFinalize; } if (finalizeCallback != nullptr) finalizeCallback(); @@ -107,6 +106,13 @@ void finalize() { heapFinalized = true; } +struct HeapFinalizerRegistration { + HeapFinalizerRegistration() { + if (std::atexit(finalize) != 0) std::terminate(); + } +}; +const HeapFinalizerRegistration heapFinalizerRegistration; + } void ApplicationHeapRegister_nid_no_patch(void* const* api) { @@ -144,7 +150,6 @@ void ApplicationHeapInitialize_nid_no_patch(const void* processParameters) { std::lock_guard lock(heapMutex); heapFinalize = read(replacement, 0x18); } - if (std::atexit(finalize) != 0) throw std::runtime_error("application heap: cannot register finalization"); } catch (...) { std::lock_guard lock(heapMutex); heapFailure = std::current_exception(); diff --git a/core/libs/tests/ApplicationHeap.cpp b/core/libs/tests/ApplicationHeap.cpp index 0f08924bb..088f79122 100644 --- a/core/libs/tests/ApplicationHeap.cpp +++ b/core/libs/tests/ApplicationHeap.cpp @@ -17,6 +17,7 @@ void* ApplicationHeapRealign_nid_no_patch(void*, std::size_t, std::size_t); char* APS5_VABI strdup_nid_postfix(const char*); char* APS5_VABI strndup_nid_postfix(const char*, std::size_t); int* APS5_VABI __error_nid_postfix(); +int APS5_VABI atexit_nid_postfix(void (APS5_VABI*)()); } namespace { @@ -42,6 +43,9 @@ void reject(TAction action) { void APS5_VABI initialize() { ++initializes; } void APS5_VABI finalize() { require(initializes == 1); } +void APS5_VABI exitCallbackAllocates() { + if (ApplicationHeapAllocate_nid_no_patch(16) != storage.data()) throw std::runtime_error("application heap test failed"); +} void* APS5_VABI allocate(std::size_t bytes) { lastSize = bytes; @@ -110,6 +114,12 @@ int main(int argc, char** argv) { write(replacement, 0x40, &align); write(replacement, 0x48, &realign); write(replacement, 0x50, &posixAlign); + if (argc > 1 && std::strcmp(argv[1], "exit-order") == 0) { + require(atexit_nid_postfix(exitCallbackAllocates) == 0); + ApplicationHeapInitialize_nid_no_patch(process.data()); + require(initializes == 1); + return 0; + } if (argc > 1 && std::strcmp(argv[1], "default") == 0) { std::array partial{}; partial[0] = reinterpret_cast(&allocate);