PPCRec: Fix function scanning reading unmapped memory

Scanning code near the start or end of a codecave could read past its memory region and crash.
This commit is contained in:
Crementif committed 2026-10-22 20:16:25 +02:00
1 parent 0e4fc41f20
commit d1ca2e987f
1 file changed
+14 -4
@@ -76,6 +76,9 @@ public:
private:
void addBranchDestination(PPCRange_t* sourceRange, MPTR address)
{
// data that gets scanned as code can decode as a branch to unmapped memory
if (!memory_isAddressRangeAccessible(address, 4))
return;
map_queuedBranchTargets.emplace(address);
map_branchTargetsAll.emplace(address);
}
@@ -131,8 +134,8 @@ private:
// if the next two or previous two instructions are branch instructions, we assume that they are destinations of a jump table
// todo - can we make this more reliable by checking for BCTR or similar instructions first?
// example: The Swapper 0x01B1FC04
if (PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address + 4)) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address + 8)) ||
PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address - 8)) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address - 4)))
if (PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(address + 4) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(address + 8) ||
PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(address - 8) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(address - 4))
{
return true;
}
@@ -165,7 +168,7 @@ private:
// Currently we only end the function if the BCTR is followed by a NOP (alignment) or invalid instruction
// todo: improve robustness, find better ways to handle false positives
uint32 nextOpcode = memory_readU32(address + 4);
uint32 nextOpcode = memory_isAddressRangeAccessible(address + 4, 4) ? memory_readU32(address + 4) : 0;
if (nextOpcode == 0x60000000 || PPCRecompilerCalcFuncSize_isValidInstruction(nextOpcode) == false)
{
@@ -221,6 +224,9 @@ private:
MPTR endAddress = 0xFFFFFFFF;
if (nextRange)
endAddress = nextRange->startAddress;
// don't scan past the end of the mapped region
if (MMURange* mmuRange = memory_getMMURangeByAddress(startAddress); mmuRange && mmuRange->getEnd() < endAddress)
endAddress = mmuRange->getEnd();
while (currentAddress < endAddress)
{
if (!processInstruction(newRange, currentAddress))
@@ -293,8 +299,12 @@ private:
}
private:
bool PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(uint32 opcode)
bool PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(MPTR address)
{
// neighbours can be unmapped
if (!memory_isAddressRangeAccessible(address, 4))
return false;
uint32 opcode = memory_readU32(address);
if (Espresso::GetPrimaryOpcode(opcode) == Espresso::PrimaryOpcode::B)
{
uint32 LI;