Repository: godotengine/godot (language: cpp)

Issue:
Godot 4.4 throws errors when using `await` on EditorPlugin
### 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](https://github.com/user-attachments/assets/24fe74ed-8acc-4ff7-b0d8-8fa50fee318a)

### 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](https://github.com/user-attachments/files/18223024/project_bad_address.zip)


Discussion / hints:
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:

<details><summary>Backtrace</summary>

```
================================================================
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 --
================================================================
```

</details>

<br>

The errors are the same (expect for the one i cited) and the backtrace looks similar from this [other issue](https://github.com/godotengine/godot/issues/97053#issuecomment-2492683547), 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.
Bisected to #94802, @Hilderin

![Image](https://github.com/user-attachments/assets/01b8ca08-0262-4ab6-9ec4-262333a04e36)

<br>

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.

<details><summary>Backtrace</summary>

```
================================================================
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 --
================================================================
```

</details>
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.
CC @godotengine/gdscript 
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)


Related to #86362
@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.
Looking at https://github.com/godotengine/godot/issues/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.

Fix patch:
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 961d81c034fd..c8b6227d1341 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3710,7 +3710,9 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
 	// Only try to load the script if it has a name. Else, the plugin has no init script.
 	if (script_path.length() > 0) {
 		script_path = addon_path.get_base_dir().path_join(script_path);
-		scr = ResourceLoader::load(script_path, "Script", ResourceFormatLoader::CACHE_MODE_IGNORE);
+		// We should not use the cached version on startup to prevent a script reload
+		// if it is already loaded and potentially running from autoloads. See GH-100750.
+		scr = ResourceLoader::load(script_path, "Script", EditorFileSystem::get_singleton()->doing_first_scan() ? ResourceFormatLoader::CACHE_MODE_REUSE : ResourceFormatLoader::CACHE_MODE_IGNORE);
 
 		if (scr.is_null()) {
 			show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path));


Test patch: