PatchEngine/GeckoCode: Heuristic stack checks

Try to make sure the stack is sane before calling into the
codehandler. This is intended to reduce the possibility of random
memory corruption.
This commit is contained in:
EmptyChaos
2016-09-30 15:29:35 +00:00
parent 31cf8432bf
commit b3547870ee
5 changed files with 78 additions and 49 deletions

View File

@ -20,6 +20,7 @@
#include <string>
#include <vector>
#include "Common/Assert.h"
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
@ -203,6 +204,32 @@ static void ApplyPatches(const std::vector<Patch>& patches)
}
}
// Requires MSR.DR, MSR.IR
// There's no perfect way to do this, it's just a heuristic.
// We require at least 2 stack frames, if the stack is shallower than that then it won't work.
static bool IsStackSane()
{
_dbg_assert_(ACTIONREPLAY, UReg_MSR(MSR).DR && UReg_MSR(MSR).IR);
// Check the stack pointer
u32 SP = GPR(1);
if (!PowerPC::HostIsRAMAddress(SP))
return false;
// Read the frame pointer from the stack (find 2nd frame from top), assert that it makes sense
u32 next_SP = PowerPC::HostRead_U32(SP);
if (next_SP <= SP || !PowerPC::HostIsRAMAddress(next_SP) ||
!PowerPC::HostIsRAMAddress(next_SP + 4))
return false;
// Check the link register makes sense (that it points to a valid IBAT address)
auto insn = PowerPC::TryReadInstruction(PowerPC::HostRead_U32(next_SP + 4));
if (!insn.valid || !insn.hex)
return false;
return true;
}
bool ApplyFramePatches()
{
// Because we're using the VI Interrupt to time this instead of patching the game with a
@ -210,7 +237,7 @@ bool ApplyFramePatches()
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
// where we can try again after the CPU hopefully returns back to the normal instruction flow.
UReg_MSR msr = MSR;
if (!msr.DR || !msr.IR)
if (!msr.DR || !msr.IR || !IsStackSane())
{
INFO_LOG(
ACTIONREPLAY,