Merge pull request #11404 from xXPBSXx/test/libc-cxa-guard-behavior

test(libc): cover the __cxa_guard_acquire, release and abort behaviour
This commit is contained in:
Dean authored and GitHub committed 2026-10-27 18:35:35 +13:00
commit ce7a561cfd
2 files changed
+114

No files matched your search

+10
View File
@@ -743,6 +743,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_qsort PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(guest_cxa_guard_tests ${LIBS_INCLUDE_DIR}/tests/GuestCxaGuard.cpp)
target_include_directories(guest_cxa_guard_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_cxa_guard_tests PRIVATE libc)
configure_windows_unwind(guest_cxa_guard_tests)
add_test(NAME guest_cxa_guard COMMAND guest_cxa_guard_tests)
set_tests_properties(guest_cxa_guard PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_cxa_guard PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(guest_strftime_tests ${LIBS_INCLUDE_DIR}/tests/GuestStrftime.cpp)
target_include_directories(guest_strftime_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_strftime_tests PRIVATE libc)
+104
View File
@@ -0,0 +1,104 @@
#include "prx/libc/include/Api.hpp"
#include <atomic>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <thread>
static void RequireAt(bool value, int line) {
if (!value) {
std::fprintf(stderr, "cxa guard check failed at line %d\n", line);
std::abort();
}
}
#define Require(value) RequireAt((value), __LINE__)
static bool Initialized(const std::uint64_t& guard) {
return (guard & 1) != 0;
}
static void WaitForStartAt(const std::atomic<bool>& started, int line) {
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
while (!started && std::chrono::steady_clock::now() < deadline) std::this_thread::sleep_for(std::chrono::milliseconds(1));
RequireAt(started, line);
}
#define WaitForStart(started) WaitForStartAt((started), __LINE__)
int main() {
{
std::uint64_t guard = 0;
Require(__cxa_guard_acquire_nid_postfix(&guard) != 0);
Require(!Initialized(guard));
__cxa_guard_release_nid_postfix(&guard);
Require(Initialized(guard));
Require(__cxa_guard_acquire_nid_postfix(&guard) == 0);
Require(Initialized(guard));
}
{
std::uint64_t guard = 0;
Require(__cxa_guard_acquire_nid_postfix(&guard) != 0);
__cxa_guard_abort_nid_postfix(&guard);
Require(!Initialized(guard));
Require(__cxa_guard_acquire_nid_postfix(&guard) != 0);
__cxa_guard_release_nid_postfix(&guard);
Require(Initialized(guard));
Require(__cxa_guard_acquire_nid_postfix(&guard) == 0);
}
{
std::uint64_t outer = 0;
std::uint64_t inner = 0;
Require(__cxa_guard_acquire_nid_postfix(&outer) != 0);
Require(__cxa_guard_acquire_nid_postfix(&inner) != 0);
__cxa_guard_release_nid_postfix(&inner);
Require(Initialized(inner) && !Initialized(outer));
__cxa_guard_release_nid_postfix(&outer);
Require(Initialized(outer));
}
{
std::uint64_t guard = 0;
Require(__cxa_guard_acquire_nid_postfix(&guard) != 0);
std::atomic<bool> started{false};
std::atomic<bool> returned{false};
std::atomic<int> result{-1};
std::thread waiter([&] {
started = true;
result = __cxa_guard_acquire_nid_postfix(&guard);
returned = true;
});
WaitForStart(started);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Require(!returned);
__cxa_guard_release_nid_postfix(&guard);
waiter.join();
Require(returned && result == 0);
Require(Initialized(guard));
}
{
std::uint64_t guard = 0;
Require(__cxa_guard_acquire_nid_postfix(&guard) != 0);
std::atomic<bool> started{false};
std::atomic<bool> returned{false};
std::atomic<int> result{-1};
std::thread waiter([&] {
started = true;
result = __cxa_guard_acquire_nid_postfix(&guard);
returned = true;
if (result != 0) __cxa_guard_release_nid_postfix(&guard);
});
WaitForStart(started);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Require(!returned);
__cxa_guard_abort_nid_postfix(&guard);
waiter.join();
Require(returned && result != 0);
Require(Initialized(guard));
}
return 0;
}