godot icon indicating copy to clipboard operation
godot copied to clipboard

get_tree().unload_current_scene() sometimes causes a silent crash, with no errors or logs

Open ashelleyPurdue opened this issue 2 years ago • 4 comments

Godot version

4.2 .NET

System information

Godot v4.2.stable.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 (NVIDIA; 31.0.15.3699) - Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz (6 Threads)

Issue description

Calling get_tree().unload_current_scene() will sometimes(but not always) cause the game immediately close, without showing any error messages, stack traces, or any other diagnostic information. Whether or not this happens seems to be completely random. This happens both in GDScript and in C#. This crash does NOT happen if I replace unload_current_scene() with the following logic:

func unload_current_scene_custom():
    var tree = get_tree()
    var oldScene = tree.current_scene
    
    tree.root.remove_child(oldScene)
    oldScene.queue_free()

Good news, though: The crash is only nondeterministic if the function is called from _process() or _physics_process(). If it's called from a signal handler, the crash happens 100% of the time. How convenient...and perplexing.

Steps to reproduce

  1. Download and run my minimal reproduction project
  2. Click the button in the middle. It will correctly switch scenes. You can do this over and over, and it'll still work.
  3. Untick the box that says "custom unload". This will switch it from using the aforementioned unload_current_scene_custom() to using the built-in unload_current_scene().
  4. Click the middle button again. It will crash, 100% of the time.
  5. Start the game up again, untick "custom unload", and then tick the box that says "Automatic". This will cause it to switch scenes every 0.1 seconds from _physics_process(). This MIGHT cause it to crash on the first try.
  6. If it hasn't crashed yet already, wait at least 30 seconds. It'll crash. Probably.
  7. Occasionally, it won't crash no matter how long you run it for. If you suspect this is happening, close the game and go back to step 5. Nine times out of ten, it'll crash instantly this time.

Minimal reproduction project

UnloadCurrentSceneCrash.zip

ashelleyPurdue avatar Dec 02 '23 23:12 ashelleyPurdue

Tested on current master at d76c1d0e516fedc535a2e394ab780cac79203477 and I can confirm the crash. Looks like this also happens at least in Godot 4.1.1, so probably not related to recent scene change rework. Tested with ASAN build, looks like the scoped lock in

https://github.com/godotengine/godot/blob/d76c1d0e516fedc535a2e394ab780cac79203477/core/object/object.cpp#L750

blows up at the end of the function scope (heap-use-after-free) during its destructor and attempted unlock because it seems like the Control this pointer has been freed during the method call. Full ASAN log, uncollapse to see it:

ASAN Crash Log
ERROR: AddressSanitizer: heap-use-after-free on address 0x11f0f04de0e0 at pc 0x7ff70c658492 bp 0x001454fd4020 sp 0x001454fd4068
READ of size 4 at 0x11f0f04de0e0 thread T0
    #0 0x7ff70c658491 in unsigned int std::__1::__cxx_atomic_load[abi:v160005]<unsigned int>(std::__1::__cxx_atomic_base_impl<unsigned int> const*, std::__1::memory_order) C:/Ohjelmointi/llvm-mingw-20230603-ucrt-x86_64/include/c++/v1/atomic:963:12
    #1 0x7ff70c65824a in std::__1::__atomic_base<unsigned int, false>::load[abi:v160005](std::__1::memory_order) const C:/Ohjelmointi/llvm-mingw-20230603-ucrt-x86_64/include/c++/v1/atomic:1550:17
    #2 0x7ff70e3e3729 in SafeNumeric<unsigned int>::get() const E:/Repositories/godot/./core/templates/safe_refcount.h:74:16
    #3 0x7ff70e3e3729 in SafeRefCount::_check_unref_safety() E:/Repositories/godot/./core/templates/safe_refcount.h:187:3
    #4 0x7ff70e3e3729 in SafeRefCount::unref() E:/Repositories/godot/./core/templates/safe_refcount.h:205:3
    #5 0x7ff70e3e3729 in _ObjectDebugLock::~_ObjectDebugLock() E:/Repositories/godot/core\object/object.cpp:55:20
    #6 0x7ff70e3ab5c7 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/core\object/object.cpp:781:1
    #7 0x7ff713b556ae in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) E:/Repositories/godot/core\variant/variant_call.cpp:1168:27
    #8 0x7ff72574a23f in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) E:/Repositories/godot/modules\gdscript/gdscript_vm.cpp:1704:12
    #9 0x7ff71efb5275 in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/modules\gdscript/gdscript.cpp:1937:21
    #10 0x7ff70e3aafe0 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/core\object/object.cpp:753:26
    #11 0x7ff70de913bf in Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const E:/Repositories/godot/core\variant/callable.cpp:69:25
    #12 0x7ff70e3b6742 in Object::emit_signalp(StringName const&, Variant const**, int) E:/Repositories/godot/core\object/object.cpp:1127:15
    #13 0x7ff7117c5efd in Node::emit_signalp(StringName const&, Variant const**, int) E:/Repositories/godot/scene\main/node.cpp:3606:17
    #14 0x7ff70ce5e208 in Error Object::emit_signal<>(StringName const&) E:/Repositories/godot/./core/object/object.h:922:10
    #15 0x7ff716d85f54 in BaseButton::_pressed() E:/Repositories/godot/scene\gui/base_button.cpp:138:2
    #16 0x7ff716d83b53 in BaseButton::on_action_event(Ref<InputEvent>) E:/Repositories/godot/scene\gui/base_button.cpp:172:5
    #17 0x7ff716d80b50 in BaseButton::gui_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\gui/base_button.cpp:69:3
    #18 0x7ff7149b26d1 in Control::_call_gui_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\gui/control.cpp:1810:2
    #19 0x7ff711489753 in Viewport::_gui_call_input(Control*, Ref<InputEvent> const&) E:/Repositories/godot/scene\main/viewport.cpp:1593:14
    #20 0x7ff7114961bf in Viewport::_gui_input_event(Ref<InputEvent>) E:/Repositories/godot/scene\main/viewport.cpp:1862:64
    #21 0x7ff7114dbaee in Viewport::push_input(Ref<InputEvent> const&, bool) E:/Repositories/godot/scene\main/viewport.cpp:3326:3
    #22 0x7ff711c29833 in Window::_window_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\main/window.cpp:1557:3
    #23 0x7ff711d5b1cf in void call_with_variant_args_helper<Window, Ref<InputEvent> const&, 0ull>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, Callable::CallError&, IndexSequence<0ull>) E:/Repositories/godot/./core/variant/binder_common.h:303:2
    #24 0x7ff711d5acdc in void call_with_variant_args<Window, Ref<InputEvent> const&>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, int, Callable::CallError&) E:/Repositories/godot/./core/variant/binder_common.h:417:2
    #25 0x7ff711d5a66a in CallableCustomMethodPointer<Window, Ref<InputEvent> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const E:/Repositories/godot/./core/object/callable_method_pointer.h:98:3
    #26 0x7ff70de907a1 in Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const E:/Repositories/godot/core\variant/callable.cpp:57:11
    #27 0x7ff70c74aff7 in Variant Callable::call<Ref<InputEvent>>(Ref<InputEvent>) const E:/Repositories/godot/./core/variant/variant.h:849:2
    #28 0x7ff70c6eb17b in DisplayServerWindows::_dispatch_input_event(Ref<InputEvent> const&) E:/Repositories/godot/platform\windows/display_server_windows.cpp:2716:14
    #29 0x7ff70c6e9acd in DisplayServerWindows::_dispatch_input_events(Ref<InputEvent> const&) E:/Repositories/godot/platform\windows/display_server_windows.cpp:2685:56
    #30 0x7ff70dc52dfa in Input::_parse_input_event_impl(Ref<InputEvent> const&, bool) E:/Repositories/godot/core\input/input.cpp:730:3
    #31 0x7ff70dc40535 in Input::flush_buffered_events() E:/Repositories/godot/core\input/input.cpp:994:3
    #32 0x7ff70c6d83aa in DisplayServerWindows::process_events() E:/Repositories/godot/platform\windows/display_server_windows.cpp:2399:27
    #33 0x7ff70c6421af in OS_Windows::run() E:/Repositories/godot/platform\windows/os_windows.cpp:1473:35
    #34 0x7ff70c622c2f in widechar_main(int, wchar_t**) E:/Repositories/godot/platform\windows/godot_windows.cpp:180:6
    #35 0x7ff70c6230dd in _main() E:/Repositories/godot/platform\windows/godot_windows.cpp:204:11
    #36 0x7ff70c62335f in main E:/Repositories/godot/platform\windows/godot_windows.cpp:223:9
    #37 0x7ff70c621314 in __tmainCRTStartup /home/runner/work/llvm-mingw/llvm-mingw/mingw-w64/mingw-w64-crt/build-x86_64/../crt/crtexe.c:267:15
    #38 0x7ff70c621155 in .l_startw /home/runner/work/llvm-mingw/llvm-mingw/mingw-w64/mingw-w64-crt/build-x86_64/../crt/crtexe.c:157:9
    #39 0x7ff8b8a07343  (C:\WINDOWS\System32\KERNEL32.DLL+0x180017343)
    #40 0x7ff8ba7e26b0  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800526b0)

0x11f0f04de0e0 is located 96 bytes inside of 2392-byte region [0x11f0f04de080,0x11f0f04de9d8)
freed by thread T0 here:
    #0 0x7ffffcac2671 in free /home/runner/work/llvm-mingw/llvm-mingw/llvm-project/compiler-rt/lib/asan/asan_malloc_win.cpp:82:3
    #1 0x7ff70d8d30ca in Memory::free_static(void*, bool) E:/Repositories/godot/core\os/memory.cpp:168:3
    #2 0x7ff710a64062 in void memdelete<Node>(Node*) E:/Repositories/godot/./core/os/memory.h:112:2
    #3 0x7ff711363c66 in SceneTree::unload_current_scene() E:/Repositories/godot/scene\main/scene_tree.cpp:1443:3
    #4 0x7ff70cf3a7f8 in void call_with_variant_args_helper<__UnexistingClass>(__UnexistingClass*, void (__UnexistingClass::*)(), Variant const**, Callable::CallError&, IndexSequence<>) E:/Repositories/godot/./core/variant/binder_common.h:303:2
    #5 0x7ff70cf3a3ec in void call_with_variant_args_dv<__UnexistingClass>(__UnexistingClass*, void (__UnexistingClass::*)(), Variant const**, int, Callable::CallError&, Vector<Variant> const&) E:/Repositories/godot/./core/variant/binder_common.h:450:2
    #6 0x7ff70cf391b6 in MethodBindT<>::call(Object*, Variant const**, int, Callable::CallError&) const E:/Repositories/godot/./core/object/method_bind.h:335:3
    #7 0x7ff70e3ab4a9 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/core\object/object.cpp:775:17
    #8 0x7ff713b556ae in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) E:/Repositories/godot/core\variant/variant_call.cpp:1168:27
    #9 0x7ff72574a23f in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) E:/Repositories/godot/modules\gdscript/gdscript_vm.cpp:1704:12
    #10 0x7ff71efb5275 in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/modules\gdscript/gdscript.cpp:1937:21
    #11 0x7ff70e3aafe0 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/core\object/object.cpp:753:26
    #12 0x7ff713b556ae in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) E:/Repositories/godot/core\variant/variant_call.cpp:1168:27
    #13 0x7ff72574a23f in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) E:/Repositories/godot/modules\gdscript/gdscript_vm.cpp:1704:12
    #14 0x7ff71efb5275 in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/modules\gdscript/gdscript.cpp:1937:21
    #15 0x7ff70e3aafe0 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) E:/Repositories/godot/core\object/object.cpp:753:26
    #16 0x7ff70de913bf in Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const E:/Repositories/godot/core\variant/callable.cpp:69:25
    #17 0x7ff70e3b6742 in Object::emit_signalp(StringName const&, Variant const**, int) E:/Repositories/godot/core\object/object.cpp:1127:15
    #18 0x7ff7117c5efd in Node::emit_signalp(StringName const&, Variant const**, int) E:/Repositories/godot/scene\main/node.cpp:3606:17
    #19 0x7ff70ce5e208 in Error Object::emit_signal<>(StringName const&) E:/Repositories/godot/./core/object/object.h:922:10
    #20 0x7ff716d85f54 in BaseButton::_pressed() E:/Repositories/godot/scene\gui/base_button.cpp:138:2
    #21 0x7ff716d83b53 in BaseButton::on_action_event(Ref<InputEvent>) E:/Repositories/godot/scene\gui/base_button.cpp:172:5
    #22 0x7ff716d80b50 in BaseButton::gui_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\gui/base_button.cpp:69:3
    #23 0x7ff7149b26d1 in Control::_call_gui_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\gui/control.cpp:1810:2
    #24 0x7ff711489753 in Viewport::_gui_call_input(Control*, Ref<InputEvent> const&) E:/Repositories/godot/scene\main/viewport.cpp:1593:14
    #25 0x7ff7114961bf in Viewport::_gui_input_event(Ref<InputEvent>) E:/Repositories/godot/scene\main/viewport.cpp:1862:64
    #26 0x7ff7114dbaee in Viewport::push_input(Ref<InputEvent> const&, bool) E:/Repositories/godot/scene\main/viewport.cpp:3326:3
    #27 0x7ff711c29833 in Window::_window_input(Ref<InputEvent> const&) E:/Repositories/godot/scene\main/window.cpp:1557:3

previously allocated by thread T0 here:
    #0 0x7ffffcac2791 in malloc /home/runner/work/llvm-mingw/llvm-mingw/llvm-project/compiler-rt/lib/asan/asan_malloc_win.cpp:98:3
    #1 0x7ff70d8d186b in Memory::alloc_static(unsigned long long, bool) E:/Repositories/godot/core\os/memory.cpp:75:14
    #2 0x7ff70d8d16dc in operator new(unsigned long long, char const*) E:/Repositories/godot/core\os/memory.cpp:40:9
    #3 0x7ff70f1f6cca in Object* ClassDB::creator<Control>() E:/Repositories/godot/./core/object/class_db.h:144:10
    #4 0x7ff70e2e4ace in ClassDB::instantiate(StringName const&) E:/Repositories/godot/core\object/class_db.cpp:377:10
    #5 0x7ff711672f22 in SceneState::instantiate(SceneState::GenEditState) const E:/Repositories/godot/scene\resources/packed_scene.cpp:237:18
    #6 0x7ff711681ec1 in PackedScene::instantiate(PackedScene::GenEditState) const E:/Repositories/godot/scene\resources/packed_scene.cpp:1946:19
    #7 0x7ff70c88c372 in Main::start() E:/Repositories/godot/main/main.cpp:3430:25
    #8 0x7ff70c622b78 in widechar_main(int, wchar_t**) E:/Repositories/godot/platform\windows/godot_windows.cpp:179:6
    #9 0x7ff70c6230dd in _main() E:/Repositories/godot/platform\windows/godot_windows.cpp:204:11
    #10 0x7ff70c62335f in main E:/Repositories/godot/platform\windows/godot_windows.cpp:223:9
    #11 0x7ff70c621314 in __tmainCRTStartup /home/runner/work/llvm-mingw/llvm-mingw/mingw-w64/mingw-w64-crt/build-x86_64/../crt/crtexe.c:267:15
    #12 0x7ff70c621155 in .l_startw /home/runner/work/llvm-mingw/llvm-mingw/mingw-w64/mingw-w64-crt/build-x86_64/../crt/crtexe.c:157:9
    #13 0x7ff8b8a07343  (C:\WINDOWS\System32\KERNEL32.DLL+0x180017343)
    #14 0x7ff8ba7e26b0  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800526b0)

SUMMARY: AddressSanitizer: heap-use-after-free /include/c++/v1/atomic:963:12 in unsigned int std::__1::__cxx_atomic_load[abi:v160005]<unsigned int>(std::__1::__cxx_atomic_base_impl<unsigned int> const*, std::__1::memory_order)
Shadow bytes around the buggy address:
  0x11f0f04dde00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x11f0f04dde80: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11f0f04ddf00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11f0f04ddf80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11f0f04de000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x11f0f04de080: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd
  0x11f0f04de100: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x11f0f04de180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x11f0f04de200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x11f0f04de280: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x11f0f04de300: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==16316==ABORTING

bitsawer avatar Dec 04 '23 09:12 bitsawer

I'm also encountering random crashes in Godot 3.6, always during scene changes.

Poobslag avatar Oct 16 '24 17:10 Poobslag

My "silent crash" bugs were fixed by removing all ViewportTextures from the scene tree before unloading the scene. I tried to create a minimal reproduction project but was unable to reproduce the bug in a simpler project.

I'm leaving this information here in case someone else has problems with their Godot game suddenly exiting on a scene change -- try unassigning any ViewportTexture properties from the scene tree before unloading the scene.

Poobslag avatar Feb 22 '25 20:02 Poobslag

Hello,I'm using godot 4.3 to make a tank battle game.In world.gd I wrote a function using dfs to create a random map in the scene,and it was called in _ready().To reset the map,I wanted to switch to another scene and then switch back.I thought it was the most simple way to do that.But it brought lots of troubles.The game exits silently when switching between the scenes.However,NOT every time I called change_scene_to_file() would cause that.There is a line "await get_tree().tree_changed" right after the call to change_scene_to_file(),and I could see that the game stuck on that line for about 570ms before it exited. I tried everything I could do,but nothing worked.Is it a bug in the editor or a fault of mine?😭

xhy2008 avatar Feb 23 '25 14:02 xhy2008