mirror of
https://github.com/xenia-project/xenia.git
synced 2025-12-06 07:12:03 +01:00
[CPU] Detect and restore corrupted global_mutex pointer to prevent crashes
This commit is contained in:
parent
01ae24e46e
commit
23ec2a4c80
|
|
@ -44,6 +44,12 @@ bool BuiltinFunction::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_not_null(handler_);
|
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_);
|
handler_(thread_state->context(), arg0_, arg1_);
|
||||||
|
|
||||||
if (original_thread_state != thread_state) {
|
if (original_thread_state != thread_state) {
|
||||||
|
|
@ -129,6 +135,16 @@ bool GuestFunction::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
ThreadState::Bind(thread_state);
|
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);
|
bool result = CallImpl(thread_state, return_address);
|
||||||
|
|
||||||
if (original_thread_state != thread_state) {
|
if (original_thread_state != thread_state) {
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,16 @@ bool Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
||||||
|
|
||||||
auto context = thread_state->context();
|
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
|
// Pad out stack a bit, as some games seem to overwrite the caller by about
|
||||||
// 16 to 32b.
|
// 16 to 32b.
|
||||||
context->r[1] -= 64 + 112;
|
context->r[1] -= 64 + 112;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue