fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch#168
Open
TH3BACKLOG wants to merge 2 commits into
Open
fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch#168TH3BACKLOG wants to merge 2 commits into
TH3BACKLOG wants to merge 2 commits into
Conversation
…ting 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.
ran-j
requested changes
Jul 12, 2026
| } | ||
| } | ||
|
|
||
| // If the function's last instruction is not a branch/jump (no delay |
Owner
There was a problem hiding this comment.
Or at least reduce maybe is too verbose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FunctionEmitter::emitonly advancesctx->pcper-instruction (overwritten each iteration) or viahandleBranchDelaySlotswhen the last instruction is a branch/jump.ctx->pcstuck at its own address forever after returning.dispatchLoopthen re-readsctx->pc, looks up the same function, and calls it again — indefinitely. No crash, no exception, just a silent infinite loop with zero forward progress.Repro
Found while debugging a "silent boot hang" in a downstream game (SDBZ,
SLUS_214.42). The ELF entry point0x100008gets emitted as a standalone one-instruction function (padduw $at, $zero, $zero, no branch), anddispatchLoopspins onpc=0x100008forever — confirmed live via debugger, watchingctx->pcstay constant across repeated dispatch iterations.Fix
Track whether the last instruction processed in the loop had a delay slot (i.e. was a branch/jump). If the function's last instruction isn't one, emit an unconditional
ctx->pc = 0x<function.end>u;before closing the function body, sodispatchLoop's next lookup resumes at the following function instead of spinning on the same one.Test plan
mainsub_00100008_0x100008) previously leftctx->pcunchanged after returning