From 8dc8b5405c46ced1c611f3b38a60c2263141b7e6 Mon Sep 17 00:00:00 2001 From: Sinan KARAKAYA Date: Tue, 18 Aug 2026 11:22:02 +0200 Subject: [PATCH] Return true after queueing a guest syscall override dispatchSyscallOverride returns bool, and its caller uses that to decide whether the built-in handler still needs to run. The success path -- the one that actually queues the guest's handler as an invocation -- fell off the end of the function without returning. That is undefined behaviour, and the practical failure mode is bad: whatever happened to be in the return register decided whether the built-in syscall ran in addition to the guest's override, so a game that overrides a syscall could get the effect applied twice, or not at all, depending on the build. (cherry picked from commit 6bf1feff8bd38892f1a464322f455fe016814c5c) --- ps2xRuntime/src/lib/Kernel/Syscalls/System.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ps2xRuntime/src/lib/Kernel/Syscalls/System.cpp b/ps2xRuntime/src/lib/Kernel/Syscalls/System.cpp index 3530e65bb..babcc0e80 100644 --- a/ps2xRuntime/src/lib/Kernel/Syscalls/System.cpp +++ b/ps2xRuntime/src/lib/Kernel/Syscalls/System.cpp @@ -440,6 +440,11 @@ namespace ps2_syscalls parent.r[2] = completed.r[2]; }; scheduler.invokeCurrent(std::move(invocation)); + // The invocation is queued and the caller must not fall through to the + // built-in handler. Falling off the end of a non-void function here was + // undefined behaviour: whatever happened to be in the return register + // decided whether the built-in ran as well as the guest's override. + return true; } static bool tryResolveGuestSyscallMirrorAddr(uint32_t syscallIndex, uint32_t &guestAddr)