Skip to content

Improve overall stability: fix memory leaks, crashes, and code correctness#119

Open
shiena wants to merge 16 commits intostechyo:masterfrom
shiena:improve/stability
Open

Improve overall stability: fix memory leaks, crashes, and code correctness#119
shiena wants to merge 16 commits intostechyo:masterfrom
shiena:improve/stability

Conversation

@shiena
Copy link

@shiena shiena commented Feb 15, 2026

Summary

Stability and robustness improvements based on code review. Fixes memory leaks, crashes, deadlocks, and strengthens error handling and type safety.

Changes

Memory leaks / Resource management

  • Release IPL effects (reflection, ambisonics encode/decode) in player destructor (fixes Memory leak when creating new SteamAudioPlayer #77)
  • Remove extra iplSceneRetain that prevented scene from being freed
  • Use auto& in range-for loops so iplStaticMeshRelease nullifies actual vector elements

Crash / Deadlock fixes

  • Fix destructor deadlock: notify condition variable after is_running=false so reflection thread can exit
  • Fix null thread access: check refl_thread.is_valid() before wait_to_finish()
  • Add null checks for mesh/shape before creating IPL static meshes
  • Handle EXIT_TREE notification in Player and Listener to prevent dangling pointers
  • Clamp mixed frame count to audio buffer size to prevent buffer overrun

Error handling

  • Add handleErr() checks for iplSourceCreate, iplDirectEffectCreate, iplReflectionEffectCreate, iplAudioBufferAllocate, iplStaticMeshCreate

Type safety / Code correctness

  • Fix header guard naming and function declarations in register_types.hpp
  • Fix return type mismatch in get_inner_stream_playback() null case
  • Add default case to log_callback switch to handle future log levels
  • Change embree_dev from static to inline in header to fix ODR violation
  • Initialize uninitialized member variables (parent, is_active, is_init)
  • Fix float/int type mismatch in config getters/setters

Minor improvements

  • Remove redundant duplicate is_local_state_init.store(false) in destructor
  • Limit panning/attenuation warnings to once per player instance

Rename GDEXAMPLE_ header guard to STEAM_AUDIO_ to match project
convention. Fix init_ext/uninit_ext declarations to match their
definitions which take ModuleInitializationLevel parameter.
The same value was stored twice in succession with no intervening code.
Use Ref<AudioStreamPlayback> instead of Ref<AudioStream> to match the
function's declared return type.
Prevents use of uninitialized godot_log_level if Steam Audio adds new
log levels in the future.
static in a header creates separate copies per translation unit (ODR
violation). inline ensures a single shared instance across all TUs.
- SteamAudioStream::parent = nullptr
- SteamAudioStreamPlayback::is_active{false}
- SteamAudioDynamicGeometry::is_init{false}

Matches the pattern used by SteamAudioGeometry which properly initializes
its atomic booleans in its constructor.
num_refl_threads and max_num_refl_srcs are int members but had float
getters/setters, causing implicit truncation. Changed to int to match
the member types and Variant::INT property bindings.
iplStaticMeshRelease takes a pointer and nullifies the handle. Using
auto (copy) meant the vector's handles were not nullified. Changed to
auto& so the release operates on the actual vector elements.
Previously these warnings were emitted every frame, flooding the
console and impacting performance.
- Notify the condition variable after setting is_running=false so the
  reflection thread can wake up and exit its wait loop.
- Check refl_thread.is_valid() before calling wait_to_finish() to avoid
  crashing when get_global_state() was never called.

These fixes address the root cause of the crash that led to the
destructor being commented out in register_types.cpp.
iplSceneCreate already returns the scene with refcount=1. The extra
iplSceneRetain bumped it to 2, but only one iplSceneRelease was called
in the destructor, leaking the scene.
Check return values of iplSourceCreate, iplDirectEffectCreate,
iplReflectionEffectCreate, iplAudioBufferAllocate (7 calls), and
iplStaticMeshCreate using the existing handleErr() utility.
Check that MeshInstance3D has a mesh and CollisionShape3D has a shape
before attempting to create IPL static meshes. Prevents null dereference
crashes when geometry nodes have no mesh/shape assigned.
Remove local state from server when Player exits the scene tree, and
clear the listener pointer when Listener exits. This prevents dangling
pointers in the server when nodes are removed from the tree, matching
the pattern already used by SteamAudioGeometry.
If mix_audio returns more frames than the allocated IPL audio buffer
size, cap the count to frameSize to avoid writing beyond buffer bounds.
The destructor was missing release calls for reflection effect,
ambisonics decode effects (x2), and ambisonics encode effect.
These were allocated in init_local_state() but never freed,
leaking memory every time a SteamAudioPlayer was destroyed.

Fixes stechyo#77
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak when creating new SteamAudioPlayer

1 participant