Editor crashes at shutdown after first discovering a GDExtension class (_gen_extensions_docs runs after cleanup_doc)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 55/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- cpp
- Domain
- backend, documentation
Research direction
Start in editor_help.cpp at EditorHelp::_gen_extensions_docs() and compare its cleanup handling with load_script_doc_cache(), generate_doc(), and regenerate_script_doc_cache(). Confirm whether the deferred callback can run after cleanup_doc() clears doc, then guard that path and its later doc use. Reproduce with the described headless cold import of a project registering one GDExtension class; done means shutdown exits successfully and generated class help still works.
Written by the indexing model from the issue text.
Description
Tested versions
- Reproducible in
v26.2.stable.official(4f5b14abad) andv26.3.stable.official(85e5203945), official Windows builds. - Reproducible in local LLVM-MinGW builds of
85e5203945, including a build that also contains the separate shutdown fixes for #1514 and #1516. - Not run on
master, butEditorHelp::_gen_extensions_docs()there still has the same unguarded code.
System information
Windows 10 22H2 (build 19045), x86-64. Headless editor (--headless --audio-driver Dummy).
Issue description
The editor can crash at shutdown (0xC0000005) when it discovers a GDExtension that registers a class in a project that has no .godot cache yet. A plain --headless --editor --import of such a project is enough. It does not depend on what the extension does: an extension that registers one empty RefCounted subclass crashes the same way as a full addon, even when the addon's editor plugin is disabled.
This is the same bug as godotengine/godot#111048 and godotengine/godot#111645, which are still open upstream.
Cause. The documentation cache worker queues EditorHelp::_gen_extensions_docs() on the main thread with call_deferred. EditorHelp::cleanup_doc() waits for the worker, then deletes doc and sets it to null. Waiting for the worker does not remove the call it has already queued. A later message-queue flush during shutdown then runs _gen_extensions_docs(), whose first line calls doc->generate(...) on the freed database. The extension XML merge in the same function is a second unguarded use of doc. The other deferred documentation entry points in editor_help.cpp (load_script_doc_cache(), generate_doc() and regenerate_script_doc_cache()) already return early when _cleanup_in_progress is set.
Proposed fix: https://github.com/dominicbytes/redot-engine/pull/4, based on redot-26.3-stable. It makes _gen_extensions_docs() return early once cleanup has started or doc is null:
void EditorHelp::_gen_extensions_docs() {
// Deferred calls may still run after the documentation has been cleaned up.
if (_cleanup_in_progress.is_set() || !doc) {
return;
}
godotengine/godot#123658 (open) takes a broader approach that ties every deferred documentation callback to an owner object. Redot could take that once it lands in Godot, or use the minimal guard above in the meantime.
Results with the fix. These used headless LLVM-MinGW builds on Windows only. The baseline already contained the #1514 and #1516 fixes, because 26.3-stable has separate shutdown crashes even in an empty project. So the only difference between the two builds is this change.
- Minimal repro below. The baseline crashed in 5 of 5 runs. The fixed build exited 0 in 5 of 5 runs, with no errors or warnings.
- Real addon. I used a Steamworks GDExtension that exposes three classes plus compiled class XML, with its own workaround for this crash removed. Its 14-step cold-import matrix covers cold import with the editor plugin disabled and enabled, restart, game run and autoload startup.
- Baseline: both cold-import steps crashed.
- Fixed build: every step passed, with debug and with release libraries.
- Class help. In both a cold and a cached editor session, the help pages for those classes still showed their generated and compiled documentation.
Linux, macOS and the interactive editor still need testing. MSVC results are in the comments below.
Steps to reproduce
-
Build a GDExtension (godot-cpp is fine) that only registers one class at SCENE level:
class ReviewProbe : public RefCounted { GDCLASS(ReviewProbe, RefCounted) protected: static void _bind_methods() {} }; void initialize_probe(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { ClassDB::register_class<ReviewProbe>(); } }The entry function registers that initializer, sets SCENE as the minimum initialization level and returns
init(). -
Create an empty project (
config_version=5) and a second project containing the extension DLL and a.gdextensionfile that points to it. Neither project has a.godotfolder. -
Using the same editor profile for both (for example a fresh temporary
APPDATA), import the empty project first to build the documentation cache, then the extension project:<redot editor> --headless --audio-driver Dummy --path <empty project> --quit-after 120 --editor --import <redot editor> --headless --audio-driver Dummy --path <extension project> --quit-after 120 --editor --import -
Expected: both runs exit 0. Actual: the second run crashes with
0xC0000005.
Minimal reproduction project (MRP)
The steps above contain the complete extension source; the projects have no other content.
- Dominant language
- C++
- Stars
- 6.1k
- Forks
- 337
- Avg merge
- 1d 37m
- Merged PRs (30d)
- 42
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Redot-Engine/redot-engine
-
bug topic:animation
Difficulty 3/5 1-2 days Newbie friendliness 54/100
Redot-Engine/redot-engine#1552 · 3 comments ·
Maintainers usually reply within 1 day
-
AnimationTree does not respect AnimationPlayer's speed_scale or the AnimationClip's update modeOpenbug topic:animation
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Redot-Engine/redot-engine#1551 ·
Maintainers usually reply within 1 day
-
bug topic:editor topic:rendering
Difficulty 5/5 Over a week Newbie friendliness 35/100
Redot-Engine/redot-engine#1550 ·
Maintainers usually reply within 1 day
-
bug needs testing topic:core
Difficulty 4/5 3-5 days Newbie friendliness 50/100
Redot-Engine/redot-engine#1549 · 1 reaction ·
Maintainers usually reply within 1 day
-
bug enhancement topic:gdscript
Difficulty 5/5 Over a week Newbie friendliness 35/100
Redot-Engine/redot-engine#1548 ·
Maintainers usually reply within 1 day
All issues in Redot-Engine/redot-engine
Similar issues
-
(S1 - Need confirmation)
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
CleverRaven/Cataclysm-DDA#89212 ·
Maintainers usually reply within 1 day
-
Status: Needs confirmation Status: Needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
ai_p2 comp-dictionary
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
ClickHouse/ClickHouse#127261 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
NVIDIA-Omniverse/usd-brep#23 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
qbittorrent/qBittorrent#25121 ·
Maintainers usually reply within 2 days