A quiet sound at the wrong distance no longer kills the game
From Nathan's crash dump: an access violation reading 8093e920, fourteen minutes into a session, on 4.12.115. rpl4opt!PatchLevelOfDetail::SetupPatch+0xbb rpl4opt!Static3DPatchSource::StartImplementation+0x50 rpl4opt!AudioRenderer::ExecuteBackground+0x9e The faulting instruction is g_buffers[index] with index = 0x20000000 - 536 million - and the array base in eax at 0093e920, which is exactly the address it died on. So the index was garbage, and the dump says where the garbage came from: the stack slot holding info.bufferIndex. PRESET_getSampleInfo builds a SAMPLEINFO to return when it is asked for a zone the preset does not have. It sets chan, file, implemented and loop - and not bufferIndex. Every caller tests bufferIndex >= 0 before using it, so "no such zone" was meant to be rejected there; instead the test read whatever was on the stack, and passed whenever that happened to be positive. AL_getBuffer then indexed the array with it, unchecked. Why it asked for a zone that is not there: the loop runs to sourceSet.count, which was fixed when the audio source was built, from whichever level of detail was selected at the time. SetDistance re-picks the level of detail by distance on the line immediately before SetupPatch runs, and the zone counts across the recovered banks are nothing like uniform - of 200 presets, 46 have no zones at all, and the rest run 1 to 4. So a sound that moved far enough to drop to a quieter patch could ask that patch for a zone it never had. In the dump: count 3, died asking for zone 2. Fixed at all three levels, because any one of them alone would have held: the default carries bufferIndex = -1 so the existing guard works, AL_getBuffer returns AL_NONE rather than reading past its array, and SetupPatch asks for no more zones than the patch it is actually using has. Verified: the dump's own numbers reproduce arithmetically, and two full races run clean. The distance-dependent trigger itself was reasoned from the dump rather than reproduced here - it needs a sound to cross a level of detail boundary into a shorter patch - so the belt-and-braces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-1
@@ -128,8 +128,25 @@ void
|
||||
// #endif
|
||||
SAMPLEINFO info;
|
||||
|
||||
//
|
||||
// Ask this patch for no more zones than it has.
|
||||
//
|
||||
// sourceSet.count was fixed when the audio source was built, from
|
||||
// whichever level of detail was selected at the time. SetDistance
|
||||
// re-picks the level of detail by distance immediately before this
|
||||
// runs (see Static3DPatchSource::StartImplementation), and a
|
||||
// further-away patch can have fewer zones than the one the source was
|
||||
// sized for - so the count outruns this patch's zone list, and the
|
||||
// zones past the end come back as "no such zone".
|
||||
//
|
||||
int zone_count = PRESET_getNumSamples(bankID,patchID);
|
||||
if (zone_count > sourceSet.count)
|
||||
{
|
||||
zone_count = sourceSet.count;
|
||||
}
|
||||
|
||||
//Attach buffers
|
||||
for (int i=0; i < sourceSet.count; i++)
|
||||
for (int i=0; i < zone_count; i++)
|
||||
{
|
||||
info = PRESET_getSampleInfo(bankID,patchID,i);
|
||||
if (info.bufferIndex >= 0)
|
||||
|
||||
Reference in New Issue
Block a user