* Fix yaml-cpp inclusion for VS building.
* Fix double-finds for rom files in the binary directory.
* Fix archive generation targets.
* Port over Proxy's change on 2ship to old ROM deletion to search all applicable subdirectories.
A stored value with no entry in the combo map threw out of map::at while
drawing, which took the whole menu down as soon as a search matched the widget.
Fall back to the default and log the offender.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The source globs did not use CONFIGURE_DEPENDS, so adding a file under
soh/ or src/ left it out of the build until cmake was re-run by hand,
silently and with no warning.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
fmt::format returns a std::string by value, so taking c_str() of the temporary
left BeginCombo reading freed memory whenever the melee weapon state fell
outside the known cases. Hold the text in a std::string instead.
Use spdlog::fmt_lib in the save editor
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 -> 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.
gItemSlots and sExtraItemBases only cover the item IDs that live in the
inventory, but Item_Give and Item_CheckObtainability index them with any
item ID. Reading past gItemSlots lands on gUpgradeShifts, so
INV_CONTENT(ITEM_SKULL_TOKEN) resolved to the Bow slot and stored the
token there, permanently corrupting the save.
Route both through a bounds-checked Item_GetSlot that reports SLOT_NONE
for items that have no slot, and skip the inventory store in that case.
That read is also undefined behaviour, which link-time optimization is
free to exploit: with it present clang dropped the ITEM_SKULL_TOKEN
branch and the ITEM_MEDALLION_WATER horse fixup from Item_Give
entirely, so tokens were never counted either.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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 >= sequenceMapSize
- AudioLoad_SyncLoadSeq: skip the in-progress check for OOB seqIds
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>