Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Godot 4.4 throws errors when using await on EditorPlugin #100750

Closed
WagnerGFX opened this issue Dec 22, 2024 · 8 comments · Fixed by #102535 · May be fixed by #102521
Closed

Godot 4.4 throws errors when using await on EditorPlugin #100750

WagnerGFX opened this issue Dec 22, 2024 · 8 comments · Fixed by #102535 · May be fixed by #102521

Comments

@WagnerGFX
Copy link

Tested versions

  • Reproducible: 4.4-dev1 and 4.4-dev7
  • Not Reproducible: 4.3-stable

System information

Godot v4.4.dev7 - Windows 10 (build 19045) - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1650 (NVIDIA; 32.0.15.6603) - Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 threads)

Issue description

When the editor starts up, calling code from an Autoload to an EditorPlugin with a function that uses while and await will result in either:

  • Working fine.
  • Throwing a Bad Address Index error.
  • Throwing an Internal Script error with opcode 0, 1 or 99.
  • Crashing to desktop.

Image

Steps to reproduce

The MRP will throw the error when opening the project. If it doesn't, use "Project > Reload Current Project" as sometimes it may simply work.

This problem seems to require a combination of a few situations to happen:

  • The EditorPlugin must be enabled. The issue vanishes when disabled, even if there are no changes in the script execution.
  • The function must be called from the Autoloader to the EditorPlugin, if called from inside the EditorPlugin, it works fine.
  • the EditorPlugin class must be loaded inside the function using load(). Works fine with a preloaded variable on the class scope.
  • The await must be inside the while loop.

Some background on why I'm running code like this:

  • To isolate editor access to only inside the EditorPlugin class.
  • My plugin checks for a resource file, if it doesn't exist, creates the file and updates the FileSystem if it's in editor mode.
  • After v4.2 or v4.3, the FileSystem takes a while to load and during that time any new files or requests to update are ignored.
  • I can't use preload() because EditorPlugin classes are not exported to runtime.

Minimal reproduction project (MRP)

project_bad_address.zip

@matheusmdx
Copy link
Contributor

I can reproduce this bug, i got the errors cited in this issue and this one too:

./modules/gdscript/gdscript_vm.cpp:723 - Condition ' op >= Variant::OP_MAX ' is true. Breaking..:
 res://addons/res_plugin/res_editor_plugin.gd:7 - Internal script error! Opcode: 0 (please report).

And when crashed i got this backtrace:

Backtrace
================================================================
CrashHandlerException: Program crashed with signal 11
Engine version: Godot Engine v4.4.dev.custom_build (97ef3c837263099faf02d8ebafd6c77c94d2aaba)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] _gnu_exception_handler (C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crt_handler.c:213)
[2] StringName::hash() const (./core/string/string_name.h:140)
[3] HashMapHasherDefault::hash(StringName const&) (./core/templates/hashfuncs.h:314)
[4] HashMap<StringName, MethodBind*, HashMapHasherDefault, HashMapComparatorDefault<StringName>, DefaultTypedAllocator<HashMapElement<StringName, MethodBind*> > >::_hash(StringName const&) const (./core/templates/hash_map.h:85)
[5] HashMap<StringName, MethodBind*, HashMapHasherDefault, HashMapComparatorDefault<StringName>, DefaultTypedAllocator<HashMapElement<StringName, MethodBind*> > >::_lookup_pos(StringName const&, unsigned int&) const (./core/templates/hash_map.h:106)
[6] HashMap<StringName, MethodBind*, HashMapHasherDefault, HashMapComparatorDefault<StringName>, DefaultTypedAllocator<HashMapElement<StringName, MethodBind*> > >::getptr(StringName const&) (./core/templates/hash_map.h:300)
[7] ClassDB::get_method(StringName const&, StringName const&) (./core/object/class_db.cpp:1027)
[8] Object::callp(StringName const&, Variant const**, int, Callable::CallError&) (./core/object/object.cpp:808)
[9] Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) (./core/variant/variant_call.cpp:1211)
[10] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) (./modules/gdscript/gdscript_vm.cpp:1890)
[11] GDScriptFunctionState::resume(Variant const&) (./modules/gdscript/gdscript_function.cpp:216)
[12] GDScriptFunctionState::_signal_callback(Variant const**, int, Callable::CallError&) (./modules/gdscript/gdscript_function.cpp:166)
[13] MethodBindVarArgTR<GDScriptFunctionState, Variant>::call(Object*, Variant const**, int, Callable::CallError&) const (./core/object/method_bind.h:271)
[14] Object::callp(StringName const&, Variant const**, int, Callable::CallError&) (./core/object/object.cpp:811)
[15] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (./core/variant/callable.cpp:69)
[16] CallableCustomBind::call(Variant const**, int, Variant&, Callable::CallError&) const (./core/variant/callable_bind.cpp:152)
[17] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (./core/variant/callable.cpp:57)
[18] Object::emit_signalp(StringName const&, Variant const**, int) (./core/object/object.cpp:1198)
[19] Node::emit_signalp(StringName const&, Variant const**, int) (./scene/main/node.cpp:3926)
[20] Error Object::emit_signal<>(StringName const&) (./core/object/object.h:923)
[21] EditorFileSystem::_notification(int) (./editor/editor_file_system.cpp:1569)
[22] EditorFileSystem::_notificationv(int, bool) (./editor/editor_file_system.h:143)
[23] Object::notification(int, bool) (./core/object/object.cpp:873)
[24] SceneTree::_process_group(SceneTree::ProcessGroup*, bool) (./scene/main/scene_tree.cpp:1020)
[25] SceneTree::_process(bool) (./scene/main/scene_tree.cpp:1097)
[26] SceneTree::process(double) (./scene/main/scene_tree.cpp:580)
[27] Main::iteration() (main/main.cpp:4338)
[28] OS_Windows::run() (platform/windows/os_windows.cpp:1772)
[29] widechar_main(int, wchar_t**) (platform/windows/godot_windows.cpp:180)
[30] _main() (platform/windows/godot_windows.cpp:206)
[31] main (platform/windows/godot_windows.cpp:225)
[32] __tmainCRTStartup (C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:267)
[33] WinMainCRTStartup (C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:157)
-- END OF BACKTRACE --
================================================================

The errors are the same (expect for the one i cited) and the backtrace looks similar from this other issue, the way to trigger is different but both needs the await to happen. A difference between these two is the fact this one happens in 4.4 dev 1 too but the other issue only in 4.4 dev 2 too me (the issue author said that happens in 4.3 too but i was unable to reproduce in this version). I'll try to bisect it.

@matheusmdx
Copy link
Contributor

Bisected to #94802, @Hilderin

Image


From the pr content and the fact of the other issue won't be able to trigger in 4.4 dev 1 i don't think this is the root cause, looks like this just make the problem more easier to trigger, but that is for the gd team to judge.

Also i got more errors and a slight different backtrace:

res://addons/res_plugin/res_editor_plugin.gd:7 - Internal script error! Opcode: 6881383 (please report).

res://addons/res_plugin/res_editor_plugin.gd:7 - Internal script error! Opcode: 7078000 (please report).

# With a bit more of effort i'll be able to get a negative opcode by making the int have a overflow :D
res://addons/res_plugin/res_editor_plugin.gd:7 - Internal script error! Opcode: 1759949832 (please report).
  
C:\Users\Matheus\Downloads\Godot Source\modules/gdscript/gdscript_vm.cpp:1628 - Condition ' constructor_idx < 0 || constructor_idx >= _constructors_count ' is true. Breaking..:
res://addons/res_plugin/res_editor_plugin.gd:7 - Internal script error! Opcode: 32 (please report).

C:\Users\Matheus\Downloads\Godot Source\modules/gdscript/gdscript_vm.cpp:1953 - Condition ' (ip + 3 + instr_arg_count) > _code_size ' is true. Breaking..:
res://addons/res_plugin/res_editor_plugin.gd:7 - Bad address index.

This backtrace was compiling with MSVC, the other from my first commentary was with MinGw, not sure if the compiler make difference because the other issue also has slight different backtraces with the same compiler.

Backtrace
================================================================
CrashHandlerException: Program crashed
Engine version: Godot Engine v4.3.rc.custom_build (b0a8b3a1ef4e2e5b070b89de047b00034bbab82b)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[0] strlen (minkernel\crts\ucrt\src\appcrt\string\amd64\strlen.asm:58)
[1] strlen (minkernel\crts\ucrt\src\appcrt\string\amd64\strlen.asm:58)
[2] String::copy_from (C:\Users\Matheus\Downloads\Godot Source\core\string\ustring.cpp:296)
[3] String::String (C:\Users\Matheus\Downloads\Godot Source\core\string\ustring.cpp:2444)
[4] StringName::operator String (C:\Users\Matheus\Downloads\Godot Source\core\string\string_name.h:144)
[5] GDScriptFunction::call (C:\Users\Matheus\Downloads\Godot Source\modules\gdscript\gdscript_vm.cpp:1794)
[6] GDScriptFunctionState::resume (C:\Users\Matheus\Downloads\Godot Source\modules\gdscript\gdscript_function.cpp:218)
[7] GDScriptFunctionState::_signal_callback (C:\Users\Matheus\Downloads\Godot Source\modules\gdscript\gdscript_function.cpp:166)
[8] MethodBindVarArgTR<GDScriptFunctionState,Variant>::call (C:\Users\Matheus\Downloads\Godot Source\core\object\method_bind.h:271)
[9] Object::callp (C:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:808)
[10] Callable::callp (C:\Users\Matheus\Downloads\Godot Source\core\variant\callable.cpp:69)
[11] CallableCustomBind::call (C:\Users\Matheus\Downloads\Godot Source\core\variant\callable_bind.cpp:153)
[12] Callable::callp (C:\Users\Matheus\Downloads\Godot Source\core\variant\callable.cpp:58)
[13] Object::emit_signalp (C:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:1188)
[14] Node::emit_signalp (C:\Users\Matheus\Downloads\Godot Source\scene\main\node.cpp:3896)
[15] Object::emit_signal<> (C:\Users\Matheus\Downloads\Godot Source\core\object\object.h:936)
[16] EditorFileSystem::_notification (C:\Users\Matheus\Downloads\Godot Source\editor\editor_file_system.cpp:1484)
[17] EditorFileSystem::_notificationv (C:\Users\Matheus\Downloads\Godot Source\editor\editor_file_system.h:141)
[18] Object::notification (C:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:873)
[19] SceneTree::_process_group (C:\Users\Matheus\Downloads\Godot Source\scene\main\scene_tree.cpp:965)
[20] SceneTree::_process (C:\Users\Matheus\Downloads\Godot Source\scene\main\scene_tree.cpp:1042)
[21] SceneTree::process (C:\Users\Matheus\Downloads\Godot Source\scene\main\scene_tree.cpp:528)
[22] Main::iteration (C:\Users\Matheus\Downloads\Godot Source\main\main.cpp:4108)
[23] OS_Windows::run (C:\Users\Matheus\Downloads\Godot Source\platform\windows\os_windows.cpp:1666)
[24] widechar_main (C:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:181)
[25] _main (C:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:206)
[26] main (C:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:220)
[27] WinMain (C:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:234)
[28] __scrt_common_main_seh (D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
[29] <couldn't map PC to fn name>
-- END OF BACKTRACE --
================================================================

@Hilderin
Copy link
Contributor

Hilderin commented Feb 6, 2025

This issue has been assign to me but I'll not be able to resolve it. My PR only put in invidence another issue that was already there like @matheusmdx said. If you want, I can revert #94802 because I have no idea how await works in GDScript and no idea what a Opcode is.

@akien-mga
Copy link
Member

CC @godotengine/gdscript

@HolonProduction
Copy link
Member

Thought I'd look a bit into the debugger to maybe learn a bit about the VM stuff. What looked odd to me was that the GDScriptFunctionState that is resumed, seems faulty. Its function doesn't match its state. The state comes from the "refresh_filesystem" function but the function is @implicit_new (or sometimes just garbage values). The instruction pointer is thus beyond the end of the code of the function, no clue what we are executing there, but it might explain why there are so many different errors. On creation the function is correctly set to refresh_filesystem but when resuming it seems to have changed. The object id of the GDScriptFunctionState stayed consistent but the memory to which function points has changed.

This happens because since #73776 the editor loads plugin scripts ignoring the cache. If the autoload is initialized before the plugins (probably some multithreading involved here since it is very inconsistent) it loads the plugin script and calls to it. Then in the plugin script a GDScriptFunctionState is created when awaiting. This function state points to some memory with the GDScript function. When the editor force loads the plugin script afterwards the script gets reloaded and frees all its functions in the process. Now the function state points to freed memory (which sometime contains a correct other function afterwards). Reverting #73776 seems to fix it for me (25 tries without error) but that's not the right solution I'd guess. As for the correct solution: it's my first time looking at the VM, I have no clue ¯\_(ツ)_/¯ (maybe having editor plugins loaded before setting up the scene tree idk)

@HolonProduction
Copy link
Member

Related to #86362

@matheusmdx
Copy link
Contributor

@HolonProduction Not sure if this info can helps but the problem seems to be something with the signal emission. This issue and others like #97053 and #101059 all have the common thing the use of await keyword but #100985 throw the same errors and don't use await anywhere, so the only thing they have in common is the fact the error happens in the line related with a signal.

@HolonProduction
Copy link
Member

Looking at #100985 the instruction pointer is also beyond the code size, but it doesn't receive the instruction pointer from a saved state, so there has to be a different cause with that issue. It just looks identical on the surface, because in both cases the VM starts executing memory that isn't Gdscript byte code (at least that's how I understand it), but there are different causes I'd say.

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