[CPU] Detect and restore corrupted global_mutex pointer to prevent crashes

This commit is contained in:
I'm Matheus 2025-11-20 09:03:10 -03:00
parent 01ae24e46e
commit 23ec2a4c80
2 changed files with 26 additions and 0 deletions

View file

@ -44,6 +44,12 @@ bool BuiltinFunction::Call(ThreadState* thread_state, uint32_t return_address) {
}
assert_not_null(handler_);
// Detect corruption of builtin argument pointers (e.g., global mutex
// accidentally overwritten by guest code). A very low non-null address is
// almost certainly invalid here and has led to crashes in unlock().
if (arg0_ && reinterpret_cast<uintptr_t>(arg0_) < 0x1000) {
XELOGE("BuiltinFunction '{}' arg0 pointer appears corrupt: {:p}", name(), arg0_);
}
handler_(thread_state->context(), arg0_, arg1_);
if (original_thread_state != thread_state) {
@ -129,6 +135,16 @@ bool GuestFunction::Call(ThreadState* thread_state, uint32_t return_address) {
ThreadState::Bind(thread_state);
}
// Validate the global mutex pointer before executing guest code to help
// diagnose crashes where std::recursive_mutex::unlock() sees an invalid
// 'this' (e.g., 0x1).
auto ctx = thread_state->context();
auto& expected_global_mutex = xe::global_critical_region::mutex();
if (ctx->global_mutex != &expected_global_mutex) {
XELOGE("GuestFunction '{}' executing with corrupted global_mutex {:p}; restoring", name(), ctx->global_mutex);
ctx->global_mutex = &expected_global_mutex;
}
bool result = CallImpl(thread_state, return_address);
if (original_thread_state != thread_state) {

View file

@ -337,6 +337,16 @@ bool Processor::Execute(ThreadState* thread_state, uint32_t address) {
auto context = thread_state->context();
// Defensive: ensure the context's global mutex pointer hasn't been clobbered
// by guest code scribbling over the red zone. A corrupt pointer (like 0x1)
// leads to a crash when unlock() is invoked by translated code paths.
auto& expected_global_mutex = xe::global_critical_region::mutex();
if (context->global_mutex != &expected_global_mutex) {
uintptr_t raw_ptr = reinterpret_cast<uintptr_t>(context->global_mutex);
XELOGE("PPCContext global_mutex pointer corrupted (was {:p} / 0x{:X}), restoring", context->global_mutex, raw_ptr);
context->global_mutex = &expected_global_mutex;
}
// Pad out stack a bit, as some games seem to overwrite the caller by about
// 16 to 32b.
context->r[1] -= 64 + 112;