godot-cpp: Crash on shutdown if certain singletons were used in extension
When using certain singletons like OS::get_singleton()
from within a GDExtension it seems like internal::gdn_interface->object_get_instance_binding
in the generated get_singleton()
ends up storing callbacks on the editor side to OS::___binding_callbacks
which point to functions on the extension side.
These callbacks (___binding_free_callback
specifically) end up getting invoked on editor shutdown (at Object::~Object()
) during memdelete(_os)
in unregister_core_types()
. The problem is that by then we’ve already unloaded the extension libraries in memdelete(native_extension_manager)
, resulting in trying to call a function that no longer exists, leading to an access violation crash.
This also applies to Engine::get_singleton()
. More singletons might be affected that I haven’t run into yet.
Editor: v4.0.beta.custom_build
(ca25c6e0a)
Architecture: x86_64
Compiler: MSVC (v19.33.31630)
OS: Windows 11 (v10.0.22621)
Minimal repro:
#include <godot/gdnative_interface.h>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
using namespace godot;
void initialize_example_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
OS::get_singleton();
}
}
extern "C" {
GDNativeBool GDN_EXPORT example_library_init(
const GDNativeInterface* p_native_iface,
const GDNativeExtensionClassLibraryPtr p_native_lib,
GDNativeInitialization* p_native_init
) {
GDExtensionBinding::InitObject init_obj(p_native_iface, p_native_lib, p_native_init);
init_obj.register_initializer(initialize_example_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
} // extern "C"
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 1
- Comments: 16 (16 by maintainers)
Ah, ok, thanks!
Reading through the comments on your linked PR, Zylann brings up an important point that this issue probably affects all objects, not just singletons.
Hm, it’s starting to sound like this is a bigger, trickier problem to solve than it seemed at first! When I have the time, I’ll dig into it deeper.
That
SingletonBinder
in EffekseerForGodot4 assumes that all referenced singleton bindings call___binding_create_callback
at some point, which is not the case, and will double-free if the extension does something like expose a custom physics server, where the “binding” is effectively created by the extension itself.I’ve been running a somewhat similar hack/fix for the past couple of months, which does account for this, and seems to work as far as I know. I’m not proposing that this be merged upstream though, as I’m sure there are more esoteric interactions where this too will break.
Someone with a much deeper understanding of the godot-cpp bindings likely needs to take a closer look at the whole binding setup in godot-cpp.
If you just need a short-term fix for your own use, and you don’t mind forking/patching godot-cpp, my workaround has been working well in Godot Jolt for a good long while now.
I haven’t merged with upstream since 4.2-stable was released though, so it could be that it’s due for another touch-up, but so far they’ve all been quick and painless.
Yes, sorry, I meant that I’m surprised this issue isn’t flooded with people facing the same problem, not that I’m surprised that it hasn’t been fixed yet. It’s a tricky one.
I just feel like every non-trivial extension should run into this crash sooner or later.
Well, unfortunately, I don’t think we know how to solve it yet. I don’t remember the details, but the last time we discussed this, it was shown that this issue affects more than just singletons, but singletons are the the easiest way to trigger it.
If anyone has a proposed solution, that’d be great! Otherwise, I’ll personally look at it eventually - there’s just so many things 😃
I can’t remember if I’d only seen it in the context of the editor at that time, but yes, it most definitely happens when shutting down the game/application as well.
I know at least one other published GDExtension (Debug Draw 3D) that suffers from this issue, causing a crash on shutdown every single time for anyone who has it loaded. I’m sure there are other ones out there as well.
I’m surprised this issue hasn’t gotten more traction than it has. I guess people just don’t run their editor/game through a debugger or something?