Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/libs/prx/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ if(BUILD_TESTING)
target_link_libraries(guest_fopen_errors_tests PRIVATE libc)
add_test(NAME guest_fopen_errors COMMAND guest_fopen_errors_tests)
set_tests_properties(guest_fopen_errors PROPERTIES TIMEOUT 20)
add_test_executable(guest_atomic_assert_tests ${LIBS_INCLUDE_DIR}/tests/GuestAtomicAssert.cpp)
target_include_directories(guest_atomic_assert_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_atomic_assert_tests PRIVATE libc)
add_test(NAME guest_atomic_assert COMMAND guest_atomic_assert_tests)
set_tests_properties(guest_atomic_assert PROPERTIES TIMEOUT 10)
endif()

add_test_executable(guest_index_tests ${LIBS_INCLUDE_DIR}/tests/GuestIndex.cpp)
Expand Down
7 changes: 0 additions & 7 deletions core/libs/prx/libc/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,6 @@ extern "C" {
LibcHeapTraceInfo_nid_no_patch(info);
}

// Dead import of Cyberpunk 2077 (PPSA04029): no call sites, but the
// Windows loader resolves imports strictly, so it must be present.
int APS5_VABI _ZSt14_Atomic_assertPKcS0__nid_postfix() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

APS5_EXPORT("H2e8t5ScQGc", libc___cxa_finalize);
void APS5_VABI libc___cxa_finalize(void* dsoHandle) {
CxaFinalize_nid_no_patch(dsoHandle);
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libc/include/Api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ extern "C" {

int APS5_VABI std_execute_once_nid_postfix(int* flag, int (APS5_VABI *func)(void*, void*, void**), void* arg);
void APS5_VABI LibcHeapGetTraceInfo_nid_postfix(LibcHeapInfo* info);
int APS5_VABI _ZSt14_Atomic_assertPKcS0__nid_postfix();
[[noreturn]] void APS5_VABI _ZSt14_Atomic_assertPKcS0__nid_postfix(const char* expression, const char* function);
void APS5_VABI libc___cxa_finalize(void* dsoHandle);
char* APS5_VABI strndup_nid_postfix(const char* source, std::size_t limit);
char* APS5_VABI strdup_nid_postfix(const char* source);
Expand Down
11 changes: 11 additions & 0 deletions core/libs/prx/libc/src/StdioExtras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ int APS5_VABI sprintf_s_nid_postfix(char* buffer, size_t size, const char* forma
std::abort();
}

[[noreturn]] void APS5_VABI _ZSt14_Atomic_assertPKcS0__nid_postfix(const char* expression, const char* function) {
std::fputs(expression ? expression : "", stderr);
if (function) {
std::fputs(" in function ", stderr);
std::fputs(function, stderr);
}
std::fputs("\n", stderr);
std::fflush(stderr);
std::abort();
}

// Only the "C" locale exists.
const char* APS5_VABI setlocale_nid_postfix(int, const char* locale) {
if (locale == nullptr || locale[0] == 0 || std::strcmp(locale, "C") == 0) return "C";
Expand Down
50 changes: 50 additions & 0 deletions core/libs/tests/GuestAtomicAssert.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "prx/libc/libc.hpp"
#include <csignal>
#include <cstdlib>
#include <string>
#include <sys/wait.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif

static void Require(bool value) { if (!value) std::abort(); }

struct Outcome {
std::string output;
int status = 0;
};

static Outcome Run(const char* expression, const char* function) {
int channel[2] = {-1, -1};
Require(::pipe(channel) == 0);
const pid_t child = ::fork();
Require(child >= 0);
if (child == 0) {
::close(channel[0]);
if (::dup2(channel[1], 2) != 2) ::_exit(70);
::close(channel[1]);
#ifdef __linux__
if (::prctl(PR_SET_DUMPABLE, 0) != 0) ::_exit(71);
#endif
_ZSt14_Atomic_assertPKcS0__nid_postfix(expression, function);
}
::close(channel[1]);
Outcome outcome;
char buffer[256];
for (ssize_t count; (count = ::read(channel[0], buffer, sizeof(buffer))) > 0;) outcome.output.append(buffer, static_cast<std::size_t>(count));
::close(channel[0]);
Require(::waitpid(child, &outcome.status, 0) == child);
return outcome;
}

int main() {
const auto named = Run("invalid memory order", "atomic_load");
Require(WIFSIGNALED(named.status) && WTERMSIG(named.status) == SIGABRT);
Require(named.output == "invalid memory order in function atomic_load\n");

const auto anonymous = Run("invalid memory order", nullptr);
Require(WIFSIGNALED(anonymous.status) && WTERMSIG(anonymous.status) == SIGABRT);
Require(anonymous.output == "invalid memory order\n");
return 0;
}
Loading