Download Link Removed due to this version being out of date. Please download latest release.
Version 1.0.2.2003 — Stability & Audio Fixes
🐛 Critical Crash Fixes
Use-After-Free in Music Playback (ACCESS VIOLATION 0xC0000005)
- Root cause:
osystem_playTrack()freed the audio archive buffer (s_musicArchiveBuf) while SoLoud's audio mixing thread was still streaming from it.WavStream::loadMem()was called withaCopy=false, meaning SoLoud reads directly from the provided buffer pointer — freeing it mid-stream caused an access violation on read. - Fix: The old
WavStreamis now fully destroyed (not just stopped) before freeing the buffer, ensuring SoLoud's audio thread has completely released all references. - Previous
DiskFileobjects from the filesystem fallback path are now also properly deleted, fixing a memory leak on every track change.
Heap Corruption from malloc/delete[] Mismatch
- Root cause:
readAudioEntry()allocated buffers withmalloc(), but SoLoud'sMemoryFile::~MemoryFile()frees owned memory withdelete[]. Whenosystem_playSampleFromName()passedaTakeOwnership=true, SoLoud would laterdelete[]amalloc'd buffer — undefined behavior that silently corrupts the heap and causes delayed crashes. - Fix:
readAudioEntry()now allocates withnew unsigned char[], and all error-path deallocations usedelete[], matching SoLoud's expected deallocation mechanism.
Null Pointer Dereferences in Rendering Loop
- Root cause:
AllRedraw()inmain.cppaccessedpHybridfromHQR_Get(HQ_Hybrides)andbodyPtrfromHQR_Get(HQ_Bodys)without null checks. Certain game states returned null pointers, causing immediate crashes. - Fix: Added null checks for both
pHybridandbodyPtrwithcontinueto skip invalid entries.
🔊 Audio Fixes
Double Music Playback
- Root cause:
osystem_playTrack()always returned 0, regardless of success. The callerplayMusic()checks the return value to decide whether to skip the AdLib/OPL fallback path — returning 0 meant the AdLib music ALSO played on top of the already-playing MP3/OGG stream. - Fix:
osystem_playTrack()now returns 1 on successful playback (archive or filesystem), 0 on failure.playMusic()correctly skips the AdLib path when streaming audio is active.
Missing Null Guards in Audio System
- Added
gSoloudnull checks inosystem_playTrack()andosystemAL_udpate()to prevent crashes if the audio engine hasn't been initialized. - Added error handling for the filesystem fallback
loadFile()path — previously failed silently without cleanup.
Proper Shutdown Cleanup
closeAudioArchive()now stops and destroys the active music stream (pWavStream,pFile,s_musicArchiveBuf) before closing the archive file, preventing use-after-free during exit.
🛠 Diagnostics Improvements
Full Stack Traces in Crash Logs
- Previously:
HandleExceptioncalledLogExceptionQuietfor all exception types, producing only a one-line crash message with no stack trace — useless for debugging. - Now: Access violations and other serious crashes call
LogException, which writes a full stack trace with symbol resolution (SymFromAddr,SymGetLineFromAddr64). Heap corruption and CRT breakpoints still use the quiet logger to avoid re-entrancy issues.