mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
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:
2 files changed
+114
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user