fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch (#168)

* fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch

FunctionEmitter::emit only ever advances ctx->pc via the per-instruction
`ctx->pc = 0x<addr>u;` assignment (overwritten by the next instruction in
the same function) or via handleBranchDelaySlots when the last instruction
is a branch/jump. A function whose last instruction is neither (e.g. a
lone padduw/NOP-style instruction with no terminator) leaves ctx->pc
pointing at its own last instruction forever after returning, since
nothing ever advances it to the next function.

dispatchLoop then reads ctx->pc, looks up the same function, and calls it
again -- forever. No exception, no crash, just an infinite loop that
silently never makes forward progress.

Reproduced on SDBZ's SLUS_214.42 ELF entry point: 0x100008 is emitted as a
standalone 1-instruction function (padduw $at, $zero, $zero) with no
branch, causing dispatchLoop to spin on pc=0x100008 indefinitely.

Fix: track whether the last processed instruction had a delay slot (i.e.
was a branch/jump); if the function ends without one, emit an
unconditional ctx->pc = function.end before closing the function so
dispatchLoop resumes at the next function instead of spinning.

* review: trim overly verbose comment per ran-j feedback
This commit is contained in:
TH3BACKLOG
2026-07-13 08:50:36 -04:00
committed by GitHub
parent 81f2a7f5e1
commit 905b4edfa8
+10
View File
@@ -103,9 +103,12 @@ namespace ps2recomp
<< std::dec;
ss << "\n";
bool lastInstructionWasControlFlow = false;
for (size_t i = 0; i < instructions.size(); ++i)
{
const Instruction &inst = instructions[i];
lastInstructionWasControlFlow = inst.hasDelaySlot;
if (internalTargets.contains(inst.address))
{
@@ -223,6 +226,13 @@ namespace ps2recomp
}
}
// Fallthrough with no terminating branch: advance ctx->pc past the function so dispatchLoop doesn't re-call it forever.
if (!instructions.empty() && !lastInstructionWasControlFlow)
{
ss << " ctx->pc = 0x" << std::hex << function.end << "u;\n"
<< std::dec;
}
ss << "}\n";
return ss.str();
}