<feed xmlns='http://www.w3.org/2005/Atom'>
<title>Shipwright/soh/src/code/audio_load.c, branch Caladius-patch-1</title>
<subtitle>Ship of Harkinian: Ocarina of Time PC port</subtitle>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/'/>
<entry>
<title>Restore the realId assignment in AudioLoad_AsyncLoadInner (#7105)</title>
<updated>2026-08-23T12:37:51+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-08-23T12:37:51+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=945f70222a72611fe8dd1a6b59dfc6c7e512e176'/>
<id>945f70222a72611fe8dd1a6b59dfc6c7e512e176</id>
<content type='text'>
The function declares realId and then indexes with it thirteen times -
the load-status tables, AudioLoad_SearchCaches, the table entry it reads
size and address from, every cache allocation, and the status write at the
end - but nothing assigns it. It has read an uninitialised local since
"Custom Sequences" (#2066) dropped the assignment in 2022.

Restoring the line puts back the value the rest of the function expects.
For SEQUENCE_TABLE and FONT_TABLE, AudioLoad_GetRealTableIndex returns the
id unchanged, so this is only a correctness fix in practice: the paths that
reach this function today go through the sequence script's async load
command, which is rare enough that the garbage index has not been tied to
any report.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The function declares realId and then indexes with it thirteen times -
the load-status tables, AudioLoad_SearchCaches, the table entry it reads
size and address from, every cache allocation, and the status write at the
end - but nothing assigns it. It has read an uninitialised local since
"Custom Sequences" (#2066) dropped the assignment in 2022.

Restoring the line puts back the value the rest of the function expects.
For SEQUENCE_TABLE and FONT_TABLE, AudioLoad_GetRealTableIndex returns the
id unchanged, so this is only a correctness fix in practice: the paths that
reach this function today go through the sequence script's async load
command, which is rare enough that the garbage index has not been tied to
any report.</pre>
</div>
</content>
</entry>
<entry>
<title>Drop the seqLoadStatus bounds checks made redundant by #6932 (#7100)</title>
<updated>2026-08-22T14:19:04+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-08-22T14:19:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=27b71b1a54c77711caf2a4fbe76961df6504b960'/>
<id>27b71b1a54c77711caf2a4fbe76961df6504b960</id>
<content type='text'>
#6917 guarded the three seqLoadStatus accessors against sequenceMapSize
because the array was allocated at exactly that size, so a custom sequence
id past it read and wrote off the end.

#6932 sized the array to sequenceMapSize + 0xF to match sequenceMap, which
covers the whole id space rather than rejecting the ids outside it, and also
protects the writers those guards never saw: AudioHeap_AllocCached and
AudioHeap_PopCache index seqLoadStatus directly.

The guards are now not just redundant but bounded wrong - they treat the ids
in [sequenceMapSize, sequenceMapSize + 0xF) as absent from a table that now
has room for them. Nothing breaks today because every entry starts at 5, so
AudioLoad_IsSeqLoadComplete answers true regardless and
AudioLoad_SetSeqLoadStatus already declines to overwrite a 5 - but once the
heap cache path moves such an entry off 5, the guard blocks an update that
should happen.

Reverting them restores the three functions to their decompiled form. The
sizing from #6932 and the id check in AudioLoad_SyncInitSeqPlayerInternal
remain the actual protection.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
#6917 guarded the three seqLoadStatus accessors against sequenceMapSize
because the array was allocated at exactly that size, so a custom sequence
id past it read and wrote off the end.

#6932 sized the array to sequenceMapSize + 0xF to match sequenceMap, which
covers the whole id space rather than rejecting the ids outside it, and also
protects the writers those guards never saw: AudioHeap_AllocCached and
AudioHeap_PopCache index seqLoadStatus directly.

The guards are now not just redundant but bounded wrong - they treat the ids
in [sequenceMapSize, sequenceMapSize + 0xF) as absent from a table that now
has room for them. Nothing breaks today because every entry starts at 5, so
AudioLoad_IsSeqLoadComplete answers true regardless and
AudioLoad_SetSeqLoadStatus already declines to overwrite a 5 - but once the
heap cache path moves such an entry off 5, the guard blocks an update that
should happen.

Reverting them restores the three functions to their decompiled form. The
sizing from #6932 and the id check in AudioLoad_SyncInitSeqPlayerInternal
remain the actual protection.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(audio): bound audio-heap cache tables (SIGSEGV with large custom music packs) (#6932)</title>
<updated>2026-08-09T18:36:33+00:00</updated>
<author>
<name>Pedro Nascimento</name>
<email>pnascimento@gmail.com</email>
</author>
<published>2026-08-09T18:36:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=4e39d06accfa65fbed9e034c3cd7face91a6d80c'/>
<id>4e39d06accfa65fbed9e034c3cd7face91a6d80c</id>
<content type='text'>
Root cause of three identical field crashes (audio thread, opcode fetch
through a pointer with its low 32 bits overwritten, seconds after scene
transitions): AudioHeap_AllocPermanent writes permanentCache[index] with
index = permanentPool.count and no bound against the 32-entry array. In
SoH every soundfont sync-load is forced permanent, and custom sequences
whose SEQ.xml says CachePolicy="Temporary" ALSO allocate permanently
(the factory stores the LUS enum where CACHE_TEMPORARY == 0, while
AudioLoad_SyncLoad's switch reads 0 with the ROM convention
'permanent'). A pack with ~60 streamed customs plus vanilla fonts pushes
count past 32 within a session, after which each allocation sprays a
{ptr, size, tableType/id} triplet at 24-byte stride through
gAudioContext - entry[135]'s ptr field lands exactly on
seqPlayers[0].scriptState.pc and entry[156] on seqPlayers[1]'s (both
verified against the crash-dump registers).

- permanentCache raised 32 -&gt; 512 (12 KB) and AllocPermanent refuses
  allocations past the array instead of corrupting memory.
- Same unbounded-index disease fixed in the three sibling writers:
  AllocCached's persistent path (16-entry array; CACHE_EITHER degrades
  to temporary, hard persistent requests fail cleanly),
  AllocPersistentSampleCacheEntry, AllocTemporarySampleCacheEntry.
- seqLoadStatus malloc sized for the full id space (sequenceMapSize +
  0xF) matching sequenceMap; custom ids above sequenceMapSize previously
  overflowed the allocation by up to 15 bytes.

Upstream SoH bugs, not branch-introduced - this branch's many-track
packs merely made the overflow reachable in normal play. Standalone
upstreamable fix.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Root cause of three identical field crashes (audio thread, opcode fetch
through a pointer with its low 32 bits overwritten, seconds after scene
transitions): AudioHeap_AllocPermanent writes permanentCache[index] with
index = permanentPool.count and no bound against the 32-entry array. In
SoH every soundfont sync-load is forced permanent, and custom sequences
whose SEQ.xml says CachePolicy="Temporary" ALSO allocate permanently
(the factory stores the LUS enum where CACHE_TEMPORARY == 0, while
AudioLoad_SyncLoad's switch reads 0 with the ROM convention
'permanent'). A pack with ~60 streamed customs plus vanilla fonts pushes
count past 32 within a session, after which each allocation sprays a
{ptr, size, tableType/id} triplet at 24-byte stride through
gAudioContext - entry[135]'s ptr field lands exactly on
seqPlayers[0].scriptState.pc and entry[156] on seqPlayers[1]'s (both
verified against the crash-dump registers).

- permanentCache raised 32 -&gt; 512 (12 KB) and AllocPermanent refuses
  allocations past the array instead of corrupting memory.
- Same unbounded-index disease fixed in the three sibling writers:
  AllocCached's persistent path (16-entry array; CACHE_EITHER degrades
  to temporary, hard persistent requests fail cleanly),
  AllocPersistentSampleCacheEntry, AllocTemporarySampleCacheEntry.
- seqLoadStatus malloc sized for the full id space (sequenceMapSize +
  0xF) matching sequenceMap; custom ids above sequenceMapSize previously
  overflowed the allocation by up to 15 bytes.

Upstream SoH bugs, not branch-introduced - this branch's many-track
packs merely made the overflow reachable in normal play. Standalone
upstreamable fix.</pre>
</div>
</content>
</entry>
<entry>
<title>fix: seqLoadStatus OOB reads/writes for custom SAF sequences (#6917)</title>
<updated>2026-08-03T21:05:07+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-08-03T21:05:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=eafafe507ebe0dd9bb8917552c840f9f78574189'/>
<id>eafafe507ebe0dd9bb8917552c840f9f78574189</id>
<content type='text'>
Custom SAF sequence IDs can exceed sequenceMapSize, causing out-of-bounds
reads/writes on the seqLoadStatus byte array (sized exactly sequenceMapSize).

This is the direct cause of intermittent battle music failure with BGM packs
(issue #5706): on the second encounter, AudioLoad_SyncLoadSeq reads a garbage
value from heap memory past seqLoadStatus[] and may find 1 (loading in
progress), causing it to return NULL early — the sequence player is never
initialized and no battle music plays.

Symmetric fix to the fontLoadStatus guards in PR #6916:
- AudioLoad_IsSeqLoadComplete: return true for OOB seqIds (custom SAF
  sequences are resource-manager-backed, not in the async-load status table)
- AudioLoad_SetSeqLoadStatus: skip update for seqId &gt;= sequenceMapSize
- AudioLoad_SyncLoadSeq: skip the in-progress check for OOB seqIds

Co-authored-by: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Custom SAF sequence IDs can exceed sequenceMapSize, causing out-of-bounds
reads/writes on the seqLoadStatus byte array (sized exactly sequenceMapSize).

This is the direct cause of intermittent battle music failure with BGM packs
(issue #5706): on the second encounter, AudioLoad_SyncLoadSeq reads a garbage
value from heap memory past seqLoadStatus[] and may find 1 (loading in
progress), causing it to return NULL early — the sequence player is never
initialized and no battle music plays.

Symmetric fix to the fontLoadStatus guards in PR #6916:
- AudioLoad_IsSeqLoadComplete: return true for OOB seqIds (custom SAF
  sequences are resource-manager-backed, not in the async-load status table)
- AudioLoad_SetSeqLoadStatus: skip update for seqId &gt;= sequenceMapSize
- AudioLoad_SyncLoadSeq: skip the in-progress check for OOB seqIds

Co-authored-by: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>fix(audio): bounds-check fontId to stop OOB crash with large SAF packs (#6916)</title>
<updated>2026-07-13T12:12:43+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-07-13T12:12:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=fdb7e194cca951888326d67a5537336afa8acf8c'/>
<id>fdb7e194cca951888326d67a5537336afa8acf8c</id>
<content type='text'>
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 &gt;= 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 &lt;noreply@anthropic.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &gt;= 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 &lt;noreply@anthropic.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>Cleanup unused includes &amp; remove remaining LUS umbrella includes (#6813)</title>
<updated>2026-06-27T00:20:03+00:00</updated>
<author>
<name>Tim Schneeberger</name>
<email>tim.schneeberger@outlook.de</email>
</author>
<published>2026-06-27T00:20:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=633e92096964ce036e7c18426c98a4835e1aace5'/>
<id>633e92096964ce036e7c18426c98a4835e1aace5</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(audio): replace stray custom-sequence printf with a debug log (#6752)</title>
<updated>2026-06-18T13:29:45+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-06-18T13:29:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=ebdd2c34c7abccba8686a6e06741d60911cb2558'/>
<id>ebdd2c34c7abccba8686a6e06741d60911cb2558</id>
<content type='text'>
The custom-sequence registration loop printed each assigned seqNum to
stdout via a bare printf, spamming the console with context-free numbers
on every launch. Convert it to LUSLOG_DEBUG and include the sequence name
so it is hidden by default yet useful for diagnosing music-pack loading.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The custom-sequence registration loop printed each assigned seqNum to
stdout via a bare printf, spamming the console with context-free numbers
on every launch. Convert it to LUSLOG_DEBUG and include the sequence name
so it is hidden by default yet useful for diagnosing music-pack loading.</pre>
</div>
</content>
</entry>
<entry>
<title>Fix custom music corruption past 256 sequences (#5989) (#6736)</title>
<updated>2026-06-13T03:36:25+00:00</updated>
<author>
<name>David Racine</name>
<email>bass_dr@hotmail.com</email>
</author>
<published>2026-06-13T03:36:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=eb4142835eba466852cdf8d588f548a5c6d7c9fe'/>
<id>eb4142835eba466852cdf8d588f548a5c6d7c9fe</id>
<content type='text'>
The resolved replacement id (which can exceed 255) rode a single
per-player seqToPlay slot, written at enqueue but consumed
asynchronously on the audio thread; back-to-back starts and
priority-queue promotions clobbered it. sSeqFlags[0x6F] was also indexed
by raw id, reading out of bounds past the authentic range.

- func_800F9280 resolves the replacement and packs the full 16-bit id
  into the 0x82/0x85 play command; the handler reads opArgs &amp; 0xFFFF.
  Audio_QueueSeqCmd no longer pre-writes the shared slot.
- SyncInitSeqPlayerInternal uses the command-carried id and bounds-checks
  it against the calloc'd sequence map (+0xF headroom for reserved-range
  skips).
- Route sSeqFlags reads through a bounded Audio_GetSeqFlags helper.
- Warn and skip gracefully past the 16-bit id limit.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The resolved replacement id (which can exceed 255) rode a single
per-player seqToPlay slot, written at enqueue but consumed
asynchronously on the audio thread; back-to-back starts and
priority-queue promotions clobbered it. sSeqFlags[0x6F] was also indexed
by raw id, reading out of bounds past the authentic range.

- func_800F9280 resolves the replacement and packs the full 16-bit id
  into the 0x82/0x85 play command; the handler reads opArgs &amp; 0xFFFF.
  Audio_QueueSeqCmd no longer pre-writes the shared slot.
- SyncInitSeqPlayerInternal uses the command-carried id and bounds-checks
  it against the calloc'd sequence map (+0xF headroom for reserved-range
  skips).
- Route sSeqFlags reads through a bounded Audio_GetSeqFlags helper.
- Warn and skip gracefully past the 16-bit id limit.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>Fix undefined behavior (#6089)</title>
<updated>2026-01-10T21:31:21+00:00</updated>
<author>
<name>Paul Schwabauer</name>
<email>github@schwabauer.co</email>
</author>
<published>2026-01-10T21:31:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=cd8bd69c6e65c185e757133bcf67ff82ce7cf748'/>
<id>cd8bd69c6e65c185e757133bcf67ff82ce7cf748</id>
<content type='text'>
Fix TimeSplit crash on empty name

Initialize OptionValue::mVal to fix undefined behavior

Fix undefined behavior in GraveHoleJumps surface type copy.
The memcpy was reading 33 SurfaceTypes regardless of the actual count,
causing a buffer overread since NTSC 1.0 only has 31 surface types and
later versions have 32. Now uses the actual surfaceTypesCount from the
collision header.

Fix undefined behavior in framebuffer OTR signature check.
Use calloc instead of malloc for framebuffer allocation to zero-initialize
the memory. This fixes Valgrind warnings about reading uninitialized values
when ResourceMgr_OTRSigCheck reads from framebuffer pointers to check for
the "__OTR__" signature.

Fix undefined behavior in fontLoadStatus initialization.
Use calloc instead of malloc when allocating fontLoadStatus array
to ensure zero-initialization. This fixes Valgrind warnings about
conditional jumps depending on uninitialized values in
AudioLoad_SetFontLoadStatus.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Fix TimeSplit crash on empty name

Initialize OptionValue::mVal to fix undefined behavior

Fix undefined behavior in GraveHoleJumps surface type copy.
The memcpy was reading 33 SurfaceTypes regardless of the actual count,
causing a buffer overread since NTSC 1.0 only has 31 surface types and
later versions have 32. Now uses the actual surfaceTypesCount from the
collision header.

Fix undefined behavior in framebuffer OTR signature check.
Use calloc instead of malloc for framebuffer allocation to zero-initialize
the memory. This fixes Valgrind warnings about reading uninitialized values
when ResourceMgr_OTRSigCheck reads from framebuffer pointers to check for
the "__OTR__" signature.

Fix undefined behavior in fontLoadStatus initialization.
Use calloc instead of malloc when allocating fontLoadStatus array
to ensure zero-initialization. This fixes Valgrind warnings about
conditional jumps depending on uninitialized values in
AudioLoad_SetFontLoadStatus.</pre>
</div>
</content>
</entry>
<entry>
<title>Fix memory leaks in MessageViewer and audio_load (#6124)</title>
<updated>2026-01-10T12:53:37+00:00</updated>
<author>
<name>Paul Schwabauer</name>
<email>github@schwabauer.co</email>
</author>
<published>2026-01-10T12:53:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.dog6.net/Shipwright/commit/?id=5bbc32c2d1443390dc4415d62f89fab234f42a81'/>
<id>5bbc32c2d1443390dc4415d62f89fab234f42a81</id>
<content type='text'>
Add destructor to MessageViewer to free allocated buffers

Free individual strings from ResourceMgr_ListFiles before freeing the array in audio_load.c</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add destructor to MessageViewer to free allocated buffers

Free individual strings from ResourceMgr_ListFiles before freeing the array in audio_load.c</pre>
</div>
</content>
</entry>
</feed>
