Merge pull request #1001 from Dextroid17/fix/application-heap-finalize-order

fix(libc): register the application heap finalizer when libc loads
This commit is contained in:
Dean 2026-10-07 15:19:33 +13:00 committed by GitHub
commit 2129a6ef29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 5 deletions

View File

@ -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:$<TARGET_FILE_DIR:libc>")
endif()
endif()

View File

@ -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<Initialize>(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();

View File

@ -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<void*, 10> partial{};
partial[0] = reinterpret_cast<void*>(&allocate);