godotengine / godotengine/godot
CustomCallables keep a references to an old free_func on hotreload
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### Tested versions
Godot 4.4 dafc4739
### System information
linux
### Issue description
When creating a custom callable, and connecting it to a node, if the extension from which the callable was create gets reloaded (hotreload), the editor may/will crash.
I tracked it down to the `free_func` called [here](https://github.com/godotengine/godot/blob/dafc47390c39a6be75cf1705f527ccc1b38a32b0/core/extension/gdextension_interface.cpp#L234) _(but i guess any other `ffi_func` would do the trick)_
i've added `WARN_PRINT` around it (on a local copy of this commit) and it clearly crashes calling it
```cpp
~CallableCustomExtension() {
WARN_PRINT("before free");
if (free_func != nullptr) {
free_func(userdata);
}
WARN_PRINT("after free");
}
```
I get this output on the terminal (trying to reload the project after recompiling)
```bash
Building for architecture x86_64 on platform linux
scons: done reading SConscript files.
scons: Building targets ...
scons: `godot-cpp/bin/libgodot-cpp.linux.template_debug.x86_64.a' is up to date.
Compiling shared src/example.cpp ...
Linking Shared Library demo/bin/libgdexample.linux.template_debug.x86_64.so ...
scons: done building targets.
WARNING: before free
at: ~CallableCustomExtension (core/extension/gdextension_interface.cpp:233)
*** stack smashing detected ***: terminated
```
the problematic lines on the example (which is one of the [tests from godot-cpp](https://github.com/godotengine/godot-cpp/blob/master/test/src/example.cpp) with some light tweaking) is [this one](https://github.com/Ventilador/callable-crash/blob/0fb623112e508ebb14519e4a35aa05160b2cc796/src/example.cpp#L25) (having a destructor)
and [this one](https://github.com/Ventilador/callable-crash/blob/0fb623112e508ebb14519e4a35aa05160b2cc796/src/example.cpp#L117) (registering the callable on `this`)
it may be related to [this gdext-rust ticket](https://github.com/godot-rust/gdext/issues/984) or at least it's what it took me to figure out the crashes
### Steps to reproduce
1) Create a custom callable using `callable_custom_create2`
2) Rebuild your extension
3) trigger an editor refresh (with focus so it reloads the extension)
4) either Quit to Project List or Reload Project _(sometimes even changing scene tabs, i think when they where never loaded but the extension was)_
### Minimal reproduction project (MRP)
https://github.com/Ventilador/callable-crash
Contributor guide
Research direction
Start in core/extension/gdextension_interface.cpp around CallableCustomExtension::~CallableCustomExtension and the referenced free_func call. Reproduce with the linked callable-crash MRP using callable_custom_create2, rebuild the extension, and trigger an editor refresh followed by reload or quitting to the project list. Done means the custom callable no longer crashes during extension hot-reload cleanup.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100