diff options
| author | David Racine <bass_dr@hotmail.com> | 2026-07-13 08:12:43 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-13 12:12:43 +0000 |
| commit | fdb7e194cca951888326d67a5537336afa8acf8c (patch) | |
| tree | b44fe4b9b8b913f19bb7f8971e4419a7cd8a1dcd /soh | |
| parent | ff7eb482d4c8b2cab93b2123e231bcb64f285160 (diff) | |
fix(audio): bounds-check fontId to stop OOB crash with large SAF packs (#6916)
AudioLoad_IsFontLoadComplete had a stub `return true` that bypassed all
load-status checks, masking an out-of-bounds write: for large SAF packs
(many custom sequences) SetFontLoadStatus indexed fontLoadStatus[] with
fontId values larger than the fontMapSize-sized array, causing heap
corruption and semi-random crashes.
Remove the stub. Add a (size_t)fontId >= fontMapSize guard in both the
check and the setter: out-of-range IDs (custom SAF sequences that carry
no associated soundfont) are treated as "loaded" in the check and
silently skipped in the write, matching prior observable behavior while
eliminating the OOB access.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'soh')
| -rw-r--r-- | soh/src/code/audio_load.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 6b136eacd..85c0ed709 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -297,18 +297,19 @@ void AudioLoad_InitSampleDmaBuffers(s32 arg0) { gAudioContext.sampleDmaReuseQueue2WrPos = gAudioContext.sampleDmaCount - gAudioContext.sampleDmaListSize1; } +// SOH [Port] Completely reworked from decomp: SAF custom fontIds can exceed the native table; bounds-check against +// fontMapSize to avoid OOB reads. s32 AudioLoad_IsFontLoadComplete(s32 fontId) { - return true; if (fontId == 0xFF) { return true; - - } else if (gAudioContext.fontLoadStatus[fontId] >= 2) { - return true; - } else if (gAudioContext.fontLoadStatus[AudioLoad_GetRealTableIndex(FONT_TABLE, fontId)] >= 2) { + } + // Resolve indirection (identity for FONT_TABLE today, but kept for parity with other tables). + fontId = (s32)AudioLoad_GetRealTableIndex(FONT_TABLE, (u32)fontId); + if ((size_t)fontId >= fontMapSize) { + // No entry in the font map — SAF sequence with no associated soundfont, treat as ready. return true; - } else { - return false; } + return gAudioContext.fontLoadStatus[fontId] >= 2; } s32 AudioLoad_IsSeqLoadComplete(s32 seqId) { @@ -336,7 +337,7 @@ s32 AudioLoad_IsSampleLoadComplete(s32 sampleBankId) { } void AudioLoad_SetFontLoadStatus(s32 fontId, s32 status) { - if ((fontId != 0xFF) && (gAudioContext.fontLoadStatus[fontId] != 5)) { + if ((fontId != 0xFF) && ((size_t)fontId < fontMapSize) && (gAudioContext.fontLoadStatus[fontId] != 5)) { gAudioContext.fontLoadStatus[fontId] = status; } } |
