Files
ARMSX2/tests
Brian Degenhardt 47614daa67 IOP: scan past non-overlapping neighbours when hunting straddlers
psxRecClearMem walks down through recBlocks from the block containing the
written word to pick up straddlers — blocks that start below it but whose
bodies reach into the range being cleared. recBlocks is ordered by startpc,
not by end address, so stopping at the first block that ends before the
write is unsound: a longer block lower down can jump clean over a short one
and still cover the write, and the scan quits before it is ever examined.

The straddler is then neither removed from recBlocks nor LUT-reset, so it
keeps executing stale code. This is the IOP half of the same blind spot
3ac41e05bd fixed on the EE; both stops came from 801d71f7f0 (2009), which
added them to iR3000A and iR5900 in one commit and is still upstream in
both.

Scan past a non-overlapping neighbour instead of stopping on it, bounded by
s_maxBlockBytes — the longest guest extent compiled since the last reset, so
the walk still terminates as soon as nothing below could reach. The scan
cursor is split from the removal start, so a skipped survivor never becomes
the base of the removal range.

Unlike the EE, IOP blocks have no 4KB page break (psxRecRecompile ends them
only at a branch or an already-compiled head), so the mark has no structural
cap beyond the 0xffff-instruction assert. IOP blocks are short in practice;
the cost is flat-array reads either way.

New gate ClearScansPastNonOverlappingNeighborToStraddlerBelow builds the
geometry the bug needs — A long, H compiled mid-A, then B truncated against
H's compiled head, which is the only way to get a block that both starts
inside A and ends before A does. It pokes a word inside A past B's end and
requires A to run the new instruction. Red before this change with the JIT
returning the stale 0x11 against the interpreter's 0x22, green after.

recompiler_tests 1439/1439.
2026-07-25 16:06:14 -07:00
..