Repository navigation
fix(libSceNgs2.native): keep the system list and its mutex alive through static teardown - #1197
Merged
oneandonlydean merged 1 commit intoOct 7, 2026
Conversation
…ugh static teardown sceNgs2SystemRender and the other entry points look up their handles in a function-local std::vector guarded by a function-local std::recursive_mutex. Both were destroyed with the other statics when the process exits, while a title's audio thread can still be rendering: std::exit runs the destructors on the exiting thread and other threads keep running until the process ends. The freed vector then no longer holds the system, so rendering returns SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE, and a lookup that walks the racks reads freed memory and crashes. Both are now allocated once and never destroyed, as other driver state that must outlive static teardown already is. PPSA21402 (Balatro) printed "Error: sceNgs2SystemRender() 804A0230" and segfaulted in Ngs2FindVoice (from sceNgs2VoiceGetState) when it was closed. ngs2_render now renders from an atexit handler registered before the first NGS2 call, which runs after the library's statics are destroyed; without this change it fails on that render.
This was referenced Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
NGS2 looks up every system, rack and voice handle in a function-local
std::vectorguarded by a function-localstd::recursive_mutex(System.cpp). Both were destroyed with the other statics when the process exits.std::exitruns the destructors on the exiting thread while the title's other threads keep running, so an audio thread that renders during exit finds the freed vector:sceNgs2SystemRenderreturnsSCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE(the freed vector's first element now holds the allocator's free-list pointer), andNgs2FindVoicefromsceNgs2VoiceGetState) dereferences freed memory and segfaults.Both objects are now allocated once and never destroyed, as other driver state that must outlive static teardown already is (
Draw.cpp,Pipeline.cpp,Recorder.cpp).Tested
Pop!_OS 24.04 (kernel 7.1.5), GCC 13.3.0, CMake 3.28.3, Ninja, Release,
BUILD_TESTING=ON, SPIRV-Tools validation off, NVIDIA GeForce RTX 4050 Laptop GPU.libspackaging pass.ctest: 390 of 390 pass.ngs2_rendernow registers anatexithandler before its first NGS2 call. The handler runs after the library's statics are destroyed, renders a system created at the end ofmainand destroys it. Without this change it fails on that render (sceNgs2SystemRenderdoes not returnSCE_NGS2_OK).main+ feat(libSceNgs2.native): implement sceNgs2ParseWaveformFile and parse 16-bit PCM waveforms #1020, fix(guest-arena): place guest address space in the PS5 window on Linux #861, feat(libSceNgs2.native): stream 16-bit PCM waveforms through appended waveform blocks #1038 and fix(agc): read indirect register lists when the command buffer is submitted #1100, which it needs to reach its menu here. The title was closed throughSDL_QUIT(SIGTERM) after 20 to 45 s. Without this change 4 of 6 runs printedError: sceNgs2SystemRender() 804A0230and 4 of 6 ended with a segfault (the core dump examined:Ngs2FindVoicecalled fromsceNgs2VoiceGetState). With it, 6 of 6 exited with status 0 and no NGS2 error.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)Ngs2Render.cppor NGS2)