mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-10 10:51:44 +00:00
pi: bounds-check do_rom_read; zero-fill on out-of-range DMA
Audio engine code paths in some games (Pokemon Stadium with the caller-context fragment-vaddr override active) compute wave-bank ROM offsets from corrupted SoundBank fields, causing __amDMA to issue PI DMAs from physical addresses past the cart ROM end. Previously do_rom_read computed `rom.data() + (phys - rom_base)` without checking bounds — any out-of-range physical address read host memory past the ROM buffer, almost always causing an access violation that killed the process. Bounds-check the computed offset and the size against rom.size(). On out-of-range, zero-fill the destination and log the bad DMA. The runner survives, audio gets silence/clicks instead of garbage, and the rate-limited log surfaces the bad addresses for tracing back to the corrupted wave-bank fields. This is a defensive runtime measure, not a stub. The bad DMAs are real bugs upstream (in the recompiled audio code's data flow) — this just keeps the host process alive long enough to diagnose them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e43892bb5f
commit
97b137eeb8
1 changed files with 26 additions and 1 deletions
|
|
@ -105,7 +105,32 @@ void recomp::do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr
|
|||
// TODO handle misaligned DMA
|
||||
assert((physical_addr & 0x1) == 0 && "Only PI DMA from aligned ROM addresses is currently supported");
|
||||
assert((ram_address & 0x7) == 0 && "Only PI DMA to aligned RDRAM addresses is currently supported");
|
||||
uint8_t* rom_addr = rom.data() + physical_addr - recomp::rom_base;
|
||||
|
||||
// Bounds check: if physical_addr is past end of ROM (audio engine
|
||||
// sometimes does this when wave_list[i].base is corrupted), don't
|
||||
// crash the runner. Log the bad DMA, zero-fill the destination,
|
||||
// and continue. This is a runtime defensive measure to keep
|
||||
// diagnostic data flowing — the underlying pointer corruption
|
||||
// still needs root-cause investigation.
|
||||
const uint32_t rom_off = physical_addr - recomp::rom_base;
|
||||
if (rom_off >= rom.size() || rom_off + num_bytes > rom.size()) {
|
||||
static int s_logged = 0;
|
||||
if (s_logged < 32) {
|
||||
s_logged++;
|
||||
fprintf(stderr,
|
||||
"[do_rom_read] OUT-OF-BOUNDS phys=0x%08X off=0x%X size=0x%zX "
|
||||
"(rom_size=0x%zX) — zero-filling dst=0x%08X\n",
|
||||
physical_addr, rom_off, num_bytes, rom.size(),
|
||||
(uint32_t)(int32_t)ram_address);
|
||||
fflush(stderr);
|
||||
}
|
||||
for (size_t i = 0; i < num_bytes; i++) {
|
||||
MEM_B(i, ram_address) = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* rom_addr = rom.data() + rom_off;
|
||||
for (size_t i = 0; i < num_bytes; i++) {
|
||||
MEM_B(i, ram_address) = *rom_addr;
|
||||
rom_addr++;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue