From c088a2dd897de6c20ac8f5563700f3e455aa818b Mon Sep 17 00:00:00 2001 From: Lyuma Date: Thu, 28 Oct 2021 19:45:29 -0700 Subject: Fix crash due to reentrancy in AudioStreamPlayer* finished signal. This crash occurred when an audio stream finished playing in NOTIFICATION_INTERNAL_PROCESS, during which it would iterate through a loop of playbacks, leading to a "finished" signal, which removed the audio player from the tree which led to a NOTIFICATION_EXIT_TREE, which would mutate the array of playbacks while within the above loop. This moves the signal callback outside of the loop which avoids the crash. Note: previously, the signal was called multiple times if the same player finishes multiple times in one frame. Now it is at most once per frame. Affects AudioStreamPlayer, AudioStreamPlayer2D and AudioStreamPlayer3D --- scene/3d/audio_stream_player_3d.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'scene/3d') diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 261acbeeb9..b5e4eac5d5 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -292,7 +292,6 @@ void AudioStreamPlayer3D::_notification(int p_what) { Vector> playbacks_to_remove; for (Ref &playback : stream_playbacks) { if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { - emit_signal(SNAME("finished")); playbacks_to_remove.push_back(playback); } } @@ -305,6 +304,9 @@ void AudioStreamPlayer3D::_notification(int p_what) { active.clear(); set_physics_process_internal(false); } + if (!playbacks_to_remove.is_empty()) { + emit_signal(SNAME("finished")); + } } while (stream_playbacks.size() > max_polyphony) { -- cgit v1.2.3