godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.17k stars 21.2k forks source link

Crash with adding/removing AnimationLibraries and trying to play an animation #86691

Open viksl opened 10 months ago

viksl commented 10 months ago

Tested versions

4.2.1 stable mono, 4.2.1 (standard non-mono version).

System information

Windows 11 - Vulkan - Nvidia RTX 4070 - intel i5 13600KF

Issue description

In my project when I try to load animation library on the fly and then play animation I get random crashes with errors as below. Sometimes animation plays couple times and then crashes and sometimes it crashes immediately.

Step by step what I do:

  1. No animation is played, no library is in AnimationPlayer
  2. Load all animation libraries in Ready()
  3. On input event (_UnhandledInput) I invoke a method to play an animation which does:
  4. Check if AnimationPlayer is playing, if yes then return and don't do anything
  5. If no animation is playing then remove current AnimationLibrary if it's in animation library list
  6. Add new animation library to the animation player
  7. Play animation from this library

Nothing else is happening in my project currently, no other code, everything running on the main thread, I tried async and await a frame for things to settle down but it makes no difference.

I can stress enough the part that there're no animations in the animation player and no animations are playing when I press the button there's nothing else in the project, which makes this next step strange. If before removing and adding animation library to the animation player I call animPlayer.Stop() then I get no errors and no crashes but it makes no sense since as I mentioned I do not have any animations playing, no animations are in the animation player to begin with and I also have an if check just in case animation player was playing to return early and not do anything.

In the test project I've removed all the guards and such to keep everything to the minimum, also it's difficult to reproduce with MRP you might need to keep trying for a while, it's easier to reproduce in C# build that's why this demo has both main.gd as well as main.cs, I did crash the gdscript version too but it took a lot of time, C# is easier to crash (though it still takes more time). (my animation libraries are a lot larger in my project so chances are that since the MRP library is so small everything happens quickly thus it's more difficult to find the timing for the error while in my project it happens all the time, I can barely play more than 3 animations in succession without crashing.

GDscript version crashes with no error, I also tried --verbose mode but gdscript version still gave nothing just silently crashed but it might be a different issue or a combined one, I noticed that when trying to play an animation and then unfocusing window play (moving it) it can cause crash too but without any error messages I can't determine if this is the same issue or not that's why again I'm providing both gdscript and C# scripts.

Error message:


Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication .
   at Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr, IntPtr, Void**, Void*)
   at Godot.NativeCalls.godot_icall_4_145(IntPtr, IntPtr, Godot.NativeInterop.godot_string_name, Double, Single, Godot.)
   at Godot.AnimationPlayer.Play(Godot.StringName, Double, Single, Boolean)
   at main.PlayAnimation()
   at main._UnhandledInput(Godot.InputEvent)
   at Godot.Node.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVariantP)
   at Godot.Node3D.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVarian)
   at main.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name ByRef, Godot.NativeInterop.NativeVariantPtrArgs)
   at Godot.Bridge.CSharpInstanceBridge.Call(IntPtr, Godot.NativeInterop.godot_string_name*, Godot.NativeInterop.godot_)

I cannot share my animations from my project since these are under a non-open license but I converted them into godot resources (tres) directly and I can reproduce this issue with the MRP which has an animation from inside godot so the issue is not within my animation files.

It can take quite a while to trigger this until you get the hang of it then it's pretty easy, spam that 1 button as much as possible. I purpously removed all the guards in the MRP to make it easier to trigget, I understand it's not a good idea to remove an animation library while an animation is playing but it's really difficult to put together the MRP for this, in my project I have all the guards up and more actually, I triple checked none of them break everytime I test this.

Steps to reproduce

  1. Open the project in the mono editor preferably (details why mentioned above, otherwise check step 5 first but be aware it's more difficult to trigger this with gdscript for some reason it just takes a lot longer)
  2. Press the Play button
  3. Keep pressing number 1 above letters on your keyboard (or change the input key in Project Settings)
  4. At some point you should see the crash, prepare yourself it might take a while. (5. Drop the main.cs project from the Main node and attach main.gd to the project and go back to step 1)

Minimal reproduction project (MRP)

TestAnimLibs.zip

EDIT: I also tried awaiting caches_cleared (called it before), animation_finished, animation_libraries_updated but it did nothing apart from that it never stopped waiting.

Ekaitzsegurola commented 10 months ago

I am having the same issue randomly when calling animationPlayer.GetAnimationLibrary("").RemoveAnimation(.... and then latter recreating a new animation, or the same with animationPlayer.GetAnimationLibrary("").AddAnimation(.

In my case is because some events share the same scene animationPlayer and i set in that animationPlayer all animations... Really difficult to reproduce because i am not sure what is happening, animationPlayer is not null and animation exists in the library.

Crash message in C# (StopAnimation returns the same error)

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr, IntPtr, Void*, Void) at Godot.NativeCalls.godot_icall_1_36(IntPtr, IntPtr, Godot.NativeInterop.godot_bool) at Godot.AnimationPlayer.Stop(Boolean) at SpriteManagement.PlayAnimation(System.String, Direction, Single, Boolean) at EventCore.PlayAnimation()

Ekaitzsegurola commented 10 months ago

Set the Stop before removing the library seems to work for me too. So even if we do not Play, it does something with that library when asigned

animationPlayer.Stop(); animationPlayer.RemoveAnimationLibrary(libraryName);

PeanutButterAddict commented 10 months ago

I have been going through a similar issue and have created a test project to reproduce it using GDScript. Multiple removal, addition of libraries with playing animations around leads to a crash. In the GDScript test project, this error keeps popping up ⇾ make_animation_instance: Condition "!has_animation(p_name)" is true make_animation_instance_error make_animation_instance_error_reduced_version

Test Project https://github.com/MiniBubblegum/AnimationMixerBug.git

Steps To Reproduce Change Library Play any animations Change Library Play any animations Keep repeating these steps and the error will be produced.

zaftnotameni commented 3 months ago

I have been going through a similar issue and have created a test project to reproduce it using GDScript. Multiple removal, addition of libraries with playing animations around leads to a crash. In the GDScript test project, this error keeps popping up ⇾ make_animation_instance: Condition "!has_animation(p_name)" is true make_animation_instance_error make_animation_instance_error_reduced_version

Test Project https://github.com/MiniBubblegum/AnimationMixerBug.git

Steps To Reproduce Change Library Play any animations Change Library Play any animations Keep repeating these steps and the error will be produced.

just ran into exactly this on a personal project 4.3-rc1 and 4.3-rc2 both crash in the same way when doing too many operations with animation libraries. Running on windows 10, gdscript version (not the mono build)

zaftnotameni commented 3 months ago

Godot 4.3 rc1 and rc2 - Windows 10 - gdscript

My project was doing the following:

1) create a library 2) add animation to the library 3) configure the animation 4) play the animation 5) remove the library 6) back to step 1 with the intent to show a new animation

That was causing this crash with

Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] error(-1): no debug info in PE/COFF executable

So I tried

1) create a library 2) add animation to the library 3) configure the animation 4) play the animation 5) remove just the animation but keep the library 6) back to step 2 with the intent to show a new animation

same crash

then I tried

1) create a library 2) add animation to the library 3) configure the animation 4) play the animation 5) wipe all keys from all tracks in the animation 6) back to step 3 with the intent to show a new animation

same crash

in all the above mentioned strategies for dealing with this, it worked fine between 1 to 3 times, then it would crash (likely due to the protected memory access error mentioned by the OP, the gdscript version crashes with no specific error, just exit with signal 11 - running with verbose also shows no specific error, building a binary myself without the production flag also shows no specific errors)

I added a bunch of logs to try to pinpoint the exact line where the crash happens, for me it was when calling .play() on the animation player.

Then I went a step further and did ResourceSaver.save(library, 'res://animationlibrary.tres') right before calling play... later on loading that animation in another AnimationPlayer and playing it worked without any issues. So the crash is definitely not something related to the animation contents

workaround: for my use case, I could switch from using an animation player to doing everything with tweens, and then no more crashes, might be something that works in a pinch for others too

PixelTim commented 2 months ago

Exactly same crash when adding/removing animations from AnimationLibrary (Godot v.4.3.stable, Windows 7, GdScript). Error:

E 0:00:44:0953   make_animation_instance: Condition "!has_animation(p_name)" is true.
  <C++ Source>   scene/animation/animation_mixer.cpp:1909 @ make_animation_instance()
akien-mga commented 2 months ago

I can reproduce the issue in the latest master branch (02b16d2f544e323b7b7f57e6e992b0b8e5d8b954) on Linux.

MRP from the OP with only GDScript: TestAnimLibs.zip

Stacktrace:

================================================================
handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.4.dev.custom_build (02b16d2f544e323b7b7f57e6e992b0b8e5d8b954)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x40d00) [0x7f0b36b49d00] (??:0)
[2] CowData<char32_t>::size() const (/home/akien/Godot/godot/./core/templates/cowdata.h:183)
[3] String::size() const (/home/akien/Godot/godot/./core/string/ustring.h:218)
[4] String::length() const (/home/akien/Godot/godot/./core/string/ustring.h:277)
[5] String::is_empty() const (/home/akien/Godot/godot/./core/string/ustring.h:429 (discriminator 1))
[6] StringName::StringName(String const&, bool) (/home/akien/Godot/godot/./core/string/string_name.cpp:393 (discriminator 1))
[7] AnimationPlayer::_play(StringName const&, double, float, bool) (/home/akien/Godot/godot/./scene/animation/animation_player.cpp:404 (discriminator 1))
[8] AnimationPlayer::play_with_capture(StringName const&, double, double, float, bool, Tween::TransitionType, Tween::EaseType) (/home/akien/Godot/godot/./scene/animation/animation_player.cpp:523)
[9] AnimationPlayer::play(StringName const&, double, float, bool) (/home/akien/Godot/godot/./scene/animation/animation_player.cpp:387)
[10] void call_with_variant_args_helper<__UnexistingClass, StringName const&, double, float, bool, 0ul, 1ul, 2ul, 3ul>(__UnexistingClass*, void (__UnexistingClass::*)(StringName const&, double, float, bool), Variant const**, Callable::CallError&, IndexSequence<0ul, 1ul, 2ul, 3ul>) (/home/akien/Godot/godot/./core/variant/binder_common.h:304 (discriminator 5))
[11] void call_with_variant_args_dv<__UnexistingClass, StringName const&, double, float, bool>(__UnexistingClass*, void (__UnexistingClass::*)(StringName const&, double, float, bool), Variant const**, int, Callable::CallError&, Vector<Variant> const&) (/home/akien/Godot/godot/./core/variant/binder_common.h:452)
[12] MethodBindT<StringName const&, double, float, bool>::call(Object*, Variant const**, int, Callable::CallError&) const (/home/akien/Godot/godot/./core/object/method_bind.h:345 (discriminator 1))
[13] Object::callp(StringName const&, Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./core/object/object.cpp:813 (discriminator 1))
[14] Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) (/home/akien/Godot/godot/./core/variant/variant_call.cpp:1211 (discriminator 2))
[15] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) (/home/akien/Godot/godot/./modules/gdscript/gdscript_vm.cpp:1924)
[16] GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./modules/gdscript/gdscript.cpp:2040 (discriminator 1))
[17] Object::callp(StringName const&, Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./core/object/object.cpp:791 (discriminator 1))
[18] Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) (/home/akien/Godot/godot/./core/variant/variant_call.cpp:1211 (discriminator 2))
[19] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) (/home/akien/Godot/godot/./modules/gdscript/gdscript_vm.cpp:1924)
[20] GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./modules/gdscript/gdscript.cpp:2040 (discriminator 1))
[21] bool Node::_gdvirtual__unhandled_input_call<false>(Ref<InputEvent>) (/home/akien/Godot/godot/./scene/main/node.h:385 (discriminator 2))
[22] Node::_call_unhandled_input(Ref<InputEvent> const&) (/home/akien/Godot/godot/./scene/main/node.cpp:3394 (discriminator 2))
[23] SceneTree::_call_input_pause(StringName const&, SceneTree::CallInputType, Ref<InputEvent> const&, Viewport*) (/home/akien/Godot/godot/./scene/main/scene_tree.cpp:1287)
[24] Viewport::_push_unhandled_input_internal(Ref<InputEvent> const&) (/home/akien/Godot/godot/./scene/main/viewport.cpp:3234)
[25] Viewport::push_input(Ref<InputEvent> const&, bool) (/home/akien/Godot/godot/./scene/main/viewport.cpp:3184)
[26] Window::_window_input(Ref<InputEvent> const&) (/home/akien/Godot/godot/./scene/main/window.cpp:1680)
[27] void call_with_variant_args_helper<Window, Ref<InputEvent> const&, 0ul>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, Callable::CallError&, IndexSequence<0ul>) (/home/akien/Godot/godot/./core/variant/binder_common.h:304 (discriminator 2))
[28] void call_with_variant_args<Window, Ref<InputEvent> const&>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./core/variant/binder_common.h:419)
[29] CallableCustomMethodPointer<Window, Ref<InputEvent> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/object/callable_method_pointer.h:104)
[30] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/variant/callable.cpp:57)
[31] Variant Callable::call<Ref<InputEvent> >(Ref<InputEvent>) const (/home/akien/Godot/godot/./core/variant/variant.h:866)
[32] DisplayServerX11::_dispatch_input_event(Ref<InputEvent> const&) (/home/akien/Godot/godot/platform/linuxbsd/x11/display_server_x11.cpp:4063 (discriminator 2))
[33] DisplayServerX11::_dispatch_input_events(Ref<InputEvent> const&) (/home/akien/Godot/godot/platform/linuxbsd/x11/display_server_x11.cpp:4040)
[34] Input::_parse_input_event_impl(Ref<InputEvent> const&, bool) (/home/akien/Godot/godot/./core/input/input.cpp:803)
[35] Input::flush_buffered_events() (/home/akien/Godot/godot/./core/input/input.cpp:1084)
[36] DisplayServerX11::process_events() (/home/akien/Godot/godot/platform/linuxbsd/x11/display_server_x11.cpp:5200)
[37] OS_LinuxBSD::run() (/home/akien/Godot/godot/platform/linuxbsd/os_linuxbsd.cpp:960)
[38] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x14b) [0x5e036b1] (/home/akien/Godot/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[39] /lib64/libc.so.6(+0x2a088) [0x7f0b36b33088] (??:0)
[40] /lib64/libc.so.6(__libc_start_main+0x8b) [0x7f0b36b3314b] (??:0)
[41] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5e034a5] (??:?)
-- END OF BACKTRACE --
================================================================

And I can also reproduce the crash from the other MRP in https://github.com/godotengine/godot/issues/86691#issuecomment-1888414848. Took a bit of back and forth, clicking LMB/RMB rapidly to change the animation and going left and right to change the animation library at the same time.

Stacktrace:

================================================================
handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.4.dev.custom_build (02b16d2f544e323b7b7f57e6e992b0b8e5d8b954)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x40d00) [0x7fc8d1b7cd00] (??:0)
[2] Object::get_instance_id() const (/home/akien/Godot/godot/./core/object/object.h:782)
[3] AnimationPlayer::_blend_pre_process(double, int, HashMap<NodePath, int, HashMapHasherDefault, HashMapComparatorDefault<NodePath>, DefaultTypedAllocator<HashMapElement<NodePath, int> > > const&) (/home/akien/Godot/godot/./scene/animation/animation_player.cpp:302 (discriminator 1))
[4] AnimationMixer::_process_animation(double, bool) (/home/akien/Godot/godot/./scene/animation/animation_mixer.cpp:938 (discriminator 1))
[5] AnimationMixer::_notification(int) (/home/akien/Godot/godot/./scene/animation/animation_mixer.cpp:2227)
[6] AnimationMixer::_notificationv(int, bool) (/home/akien/Godot/godot/./scene/animation/animation_mixer.h:43 (discriminator 14))
[7] AnimationPlayer::_notificationv(int, bool) (/home/akien/Godot/godot/./scene/animation/animation_player.h:39 (discriminator 3))
[8] Object::notification(int, bool) (/home/akien/Godot/godot/./core/object/object.cpp:878)
[9] SceneTree::_process_group(SceneTree::ProcessGroup*, bool) (/home/akien/Godot/godot/./scene/main/scene_tree.cpp:1019)
[10] SceneTree::_process(bool) (/home/akien/Godot/godot/./scene/main/scene_tree.cpp:1092 (discriminator 2))
[11] SceneTree::process(double) (/home/akien/Godot/godot/./scene/main/scene_tree.cpp:582)
[12] Main::iteration() (/home/akien/Godot/godot/main/main.cpp:4337 (discriminator 3))
[13] OS_LinuxBSD::run() (/home/akien/Godot/godot/platform/linuxbsd/os_linuxbsd.cpp:962 (discriminator 1))
[14] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x14b) [0x5e036b1] (/home/akien/Godot/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[15] /lib64/libc.so.6(+0x2a088) [0x7fc8d1b66088] (??:0)
[16] /lib64/libc.so.6(__libc_start_main+0x8b) [0x7fc8d1b6614b] (??:0)
[17] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5e034a5] (??:?)
-- END OF BACKTRACE --
================================================================

CC @TokageItLab

akien-mga commented 2 months ago

See also the MRP in #96794 which seems to be the same issue as the OP (similar stacktrace and reproduction steps) and was bisected to https://github.com/godotengine/godot/pull/80813.