Repository: godotengine/godot (language: cpp)

Issue:
Occassional crash when selecting node to add via "Create New Node" dialogue
### Tested versions

- Reproducible in: 4.4.beta3, 4.4.beta2, 4.4.beta1, 4.4.dev7
- Not reproducible in: 4.3-stable, 4.4.dev1, 4.4.dev4, 4.4.dev5, 4.4.dev6

### System information

Godot v4.4.beta3 - macOS Sequoia (15.1.1) - Multi-window, 2 monitors - OpenGL 3 (Compatibility) - Apple M1 Pro - Apple M1 Pro (10 threads)

### Issue description

Sometimes, when trying to add a new node via "Create New Node" dialog (opened with CMD+A) the editor just crashes.
All the crash reports mentioned the EditorHelpBit:

```
ERROR: FATAL: Condition "!exists" is true.
   at: operator[] (./core/templates/hash_map.h:581)

================================================================
handle_crash: Program crashed with signal 5
Engine version: Godot Engine v4.4.beta3.official (06acfccf89ad6b900ae694a4d58ceade1967a85f)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] 1   libsystem_platform.dylib            0x0000000193310184 _sigtramp + 56
[2] 2   Godot                               0x0000000109124c8c uspoof_swap_76_godot + 501732
[3] EditorHelpBit::_update_labels() (in Godot) + 7900
[4] EditorHelpBit::parse_symbol(String const&, String const&) (in Godot) + 9068
[5] CreateDialog::select_type(String const&, bool) (in Godot) + 212
[6] CreateDialog::_item_selected() (in Godot) + 68
[7] Object::emit_signalp(StringName const&, Variant const**, int) (in Godot) + 580
[8] Tree::select_single_item(TreeItem*, TreeItem*, int, TreeItem*, bool*, bool) (in Godot) + 576
[9] Tree::select_single_item(TreeItem*, TreeItem*, int, TreeItem*, bool*, bool) (in Godot) + 1380
[10] Tree::select_single_item(TreeItem*, TreeItem*, int, TreeItem*, bool*, bool) (in Godot) + 1380
[11] Tree::select_single_item(TreeItem*, TreeItem*, int, TreeItem*, bool*, bool) (in Godot) + 1380
[12] Tree::select_single_item(TreeItem*, TreeItem*, int, TreeItem*, bool*, bool) (in Godot) + 1380
[13] Tree::item_selected(int, TreeItem*) (in Godot) + 168
[14] Tree::_go_down() (in Godot) + 680
[15] Tree::gui_input(Ref<InputEvent> const&) (in Godot) + 2120
[16] CreateDialog::_sbox_input(Ref<InputEvent> const&) (in Godot) + 384
[17] GridMapEditorPlugin::~GridMapEditorPlugin()
[18] Object::emit_signalp(StringName const&, Variant const**, int) (in Godot) + 580
[19] Control::_call_gui_input(Ref<InputEvent> const&) (in Godot) + 184
[20] Viewport::_gui_input_event(Ref<InputEvent>) (in Godot) + 5992
[21] Viewport::push_input(Ref<InputEvent> const&, bool) (in Godot) + 780
[22] Window::_window_input(Ref<InputEvent> const&) (in Godot) + 348
[23] GridMapEditorPlugin::~GridMapEditorPlugin()
[24] DisplayServerMacOS::_dispatch_input_event(Ref<InputEvent> const&)
[25] DisplayServerMacOS::_dispatch_input_event(Ref<InputEvent> const&) (in Godot) + 516
[26] Input::_parse_input_event_impl(Ref<InputEvent> const&, bool) (in Godot) + 4128
[27] Input::flush_buffered_events() (in Godot) + 140
[28] DisplayServerMacOS::process_events() (in Godot) + 772
[29] OS_MacOS::run() (in Godot) + 156
[30] main (in Godot) + 388
[31] 31  dyld                                0x0000000192f58274 start + 2840
-- END OF BACKTRACE --
================================================================
```

Sometimes this happens again after several minutes, sometimes there are hours between the crashes.

### Steps to reproduce

- open the project
- open `test.gd`
- Edit the class_name to sth. different
- add node in the scene explorer and search for the changed name

### Minimal reproduction project (MRP)

[toolscripteditoraddbug.zip](https://github.com/user-attachments/files/18757024/toolscripteditoraddbug.zip)



Discussion / hints:
I also tried adding nodes like crazy in a new project with the addons mentioned above.
No crashes.
But as mentioned, sometimes there are hours of work without crashes, sometimes only minutes inbetween without big difference in "Node-add"-usage
I am now able to reproduce it and can narrow it down to:
- Create a new Script that inherits from a `BehaveNode` or descendants with a class_name
- Add node (this crashes directly or...)
- Search for the new node / class name -> Crash

I will upload an MRP when i'm home later where this happens every time now (basically an empty project with the beehave plugin added and activated)
I am unsure atm if this is a problem of beehave or the editor.
I updated the initial post with an mrp.

Basically it looks like this happens with named classes that inherit from tool classes on their inital rendering in the "Create New Node"
The beehave addon was just a coincidence bc. it uses tool annotated named classes.

I can reproduce this crash pretty consistensly, though sometimes it just works. If i restart editor then, i will get into crashes.

I tried reproducing it with Godot 4.3 but did *not* get crashes, so this seems to be introduced with 4.4
I tried the other versions and the issue seems to begin with 4.4.dev7 
Thats as much as i can do from my side atm.
Thanks a lot, I can reproduce the issue with the MRP and the steps you outlined.
I also confirm the regression seems to have been introduced in 4.4.dev7.

I don't have time to bisect right now, anyone motivated is welcome to try it, just let others know on the issue.
Here's the results of the bisection:

```
80d11500b556259ddb5b9d4548a0922a5ac1cc92 is the first bad commit
commit 80d11500b556259ddb5b9d4548a0922a5ac1cc92 (HEAD, refs/bisect/bad)
Author: Danil Alexeev <dalexeev12@yandex.ru>
Date:   Sat Dec 14 21:25:05 2024 +0300
    Code Editor: Add documentation tooltips
```

Seems #91060 added this regression. 
cc. @dalexeev 
Backtrace from gdb with line numbers (from 5da6deaaca27f3d4ec5281d5b791408570919f15):
```
ERROR: FATAL: Condition "!exists" is true.
   at: operator[] (./core/templates/hash_map.h:581)

Thread 1 "godot-git" received signal SIGILL, Illegal instruction.
0x0000000008f65bbe in HashMap<String, DocData::ClassDoc, HashMapHasherDefault, HashMapComparatorDefault<String>, DefaultTypedAllocator<HashMapElement<String, DocData::ClassDoc> > >::operator[] (
    this=0x225b8098, p_key=...) at ./core/templates/hash_map.h:581
581                     CRASH_COND(!exists);
Missing rpms, try: dnf --enablerepo='*debug*' install glibc-debuginfo-2.40-21.fc41.x86_64 fontconfig-debuginfo-2.15.0-8.fc41.x86_64 freetype-debuginfo-2.13.3-1.fc41.x86_64 libxml2-debuginfo-2.12.9-1.fc41.x86_64 zlib-ng-compat-debuginfo-2.2.3-1.fc41.x86_64 bzip2-libs-debuginfo-1.0.8-19.fc41.x86_64 libpng-debuginfo-1.6.40-4.fc41.x86_64 harfbuzz-debuginfo-9.0.0-3.fc41.x86_64 libbrotli-debuginfo-1.1.0-5.fc41.x86_64 xz-libs-debuginfo-5.6.2-2.fc41.x86_64 glib2-debuginfo-2.82.2-1.fc41.x86_64 graphite2-debuginfo-1.3.14-16.fc41.x86_64 pcre2-debuginfo-10.44-1.fc41.1.x86_64 systemd-libs-debuginfo-256.11-1.fc41.x86_64 libcap-debuginfo-2.70-4.fc41.x86_64 libgcc-debuginfo-14.2.1-7.fc41.x86_64 libX11-debuginfo-1.8.11-1.fc41.x86_64 libxcb-debuginfo-1.17.0-3.fc41.x86_64 libXau-debuginfo-1.0.11-7.fc41.x86_64 libXcursor-debuginfo-1.2.3-1.fc41.x86_64 libXrender-debuginfo-0.9.12-1.fc41.x86_64 libXfixes-debuginfo-6.0.1-4.fc41.x86_64 libxkbcommon-debuginfo-1.7.0-4.fc41.x86_64 libXext-debuginfo-1.3.6-2.fc41.x86_64 libXinerama-debuginfo-1.1.5-7.fc41.x86_64 libXrandr-debuginfo-1.5.4-4.fc41.x86_64 libXi-debuginfo-1.8.2-1.fc41.x86_64 libglvnd-glx-debuginfo-1.7.0-5.fc41.x86_64 libglvnd-debuginfo-1.7.0-5.fc41.x86_64 mesa-libGL-debuginfo-24.3.4-3.fc41.x86_64 mesa-libglapi-debuginfo-24.3.4-3.fc41.x86_64 mesa-va-drivers-freeworld-debuginfo-24.3.4-8.fc41.x86_64 libdrm-debuginfo-2.4.124-1.fc41.x86_64 libX11-xcb-debuginfo-1.8.11-1.fc41.x86_64 libXxf86vm-debuginfo-1.1.6-1.fc41.x86_64 expat-debuginfo-2.6.4-1.fc41.x86_64 llvm-libs-debuginfo-19.1.7-2.fc41.x86_64 libzstd-debuginfo-1.5.6-2.fc41.x86_64 spirv-tools-libs-debuginfo-2024.4-1.fc41.x86_64 lm_sensors-libs-debuginfo-3.6.0-20.fc41.x86_64 libxshmfence-debuginfo-1.3.2-5.fc41.x86_64 elfutils-libelf-debuginfo-0.192-7.fc41.x86_64 libstdc++-debuginfo-14.2.1-7.fc41.x86_64 libffi-debuginfo-3.4.6-3.fc41.x86_64 libedit-debuginfo-3.1-54.20250104cvs.fc41.x86_64 libpciaccess-debuginfo-0.16-13.fc41.x86_64 ncurses-libs-debuginfo-6.5-2.20240629.fc41.x86_64 dbus-libs-debuginfo-1.14.10-4.fc41.x86_64 alsa-lib-debuginfo-1.2.13-3.fc41.x86_64 pulseaudio-libs-debuginfo-17.0-2.fc41.x86_64 libsndfile-debuginfo-1.2.2-5.fc41.x86_64 libasyncns-debuginfo-0.8-29.fc41.x86_64 gsm-debuginfo-1.0.22-7.fc41.x86_64 flac-libs-debuginfo-1.4.3-5.fc41.x86_64 libvorbis-debuginfo-1.3.7-11.fc41.x86_64 opus-debuginfo-1.5.2-1.fc41.x86_64 libogg-debuginfo-1.3.5-9.fc41.x86_64 mpg123-libs-debuginfo-1.32.9-1.fc41.x86_64 lame-libs-debuginfo-3.100-18.fc41.x86_64 vulkan-loader-debuginfo-1.4.304.0-1.fc41.x86_64 mesa-vulkan-drivers-debuginfo-24.3.4-3.fc41.x86_64 libwayland-client-debuginfo-1.23.0-2.fc41.x86_64
(gdb) bt
#0  0x0000000008f65bbe in HashMap<String, DocData::ClassDoc, HashMapHasherDefault, HashMapComparatorDefault<String>, DefaultTypedAllocator<HashMapElement<String, DocData::ClassDoc> > >::operator[] (
    this=0x225b8098, p_key=...) at ./core/templates/hash_map.h:581
#1  0x0000000008ec27da in EditorHelpBit::_update_labels (this=0x156d4f60) at ./editor/editor_help.cpp:3716
#2  0x0000000008ec8379 in EditorHelpBit::parse_symbol (this=0x156d4f60, p_symbol=..., p_prologue=...) at ./editor/editor_help.cpp:4182
#3  0x0000000008e18cae in CreateDialog::select_type (this=0x15628d30, p_type=..., p_center_on_item=false) at ./editor/create_dialog.cpp:517
#4  0x0000000008e19323 in CreateDialog::_item_selected (this=0x15628d30) at ./editor/create_dialog.cpp:582
#5  0x000000000906ea14 in call_with_variant_args_helper<CreateDialog>(CreateDialog*, void (CreateDialog::*)(), Variant const**, Callable::CallError&, IndexSequence<>) (p_instance=0x15628d30, 
    p_method=(void (CreateDialog::*)(CreateDialog * const)) 0x8e192ec <CreateDialog::_item_selected()>, p_args=0x0, r_error=...) at ./core/variant/binder_common.h:315
#6  0x000000000905c81b in call_with_variant_args<CreateDialog> (p_instance=0x15628d30, p_method=(void (CreateDialog::*)(CreateDialog * const)) 0x8e192ec <CreateDialog::_item_selected()>, p_args=0x0, 
    p_argcount=0, r_error=...) at ./core/variant/binder_common.h:429
#7  0x0000000009039c3a in CallableCustomMethodPointer<CreateDialog, void>::call (this=0x156cf200, p_arguments=0x0, p_argcount=0, r_return_value=..., r_call_error=...)
    at ./core/object/callable_method_pointer.h:105
#8  0x000000000c15f603 in Callable::callp (this=0x7fffffffbfb0, p_arguments=0x0, p_argcount=0, r_return_value=..., r_call_error=...) at ./core/variant/callable.cpp:57
#9  0x000000000c4b175f in Object::emit_signalp (this=0x1569dbf0, p_name=..., p_args=0x0, p_argcount=0) at ./core/object/object.cpp:1236
#10 0x0000000009ec779e in Node::emit_signalp (this=0x1569dbf0, p_name=..., p_args=0x0, p_argcount=0) at ./scene/main/node.cpp:4021
#11 0x000000000745c0fd in Object::emit_signal<>(StringName const&) (this=0x1569dbf0, p_name=...) at ./core/object/object.h:933
#12 0x000000000a22dc71 in Tree::select_single_item (this=0x1569dbf0, p_selected=0x2e821020, p_current=0x2e821020, p_col=0, p_prev=0x0, r_in_range=0x0, p_force_deselect=false) at ./scene/gui/tree.cpp:2807
#13 0x000000000a22df01 in Tree::select_single_item (this=0x1569dbf0, p_selected=0x2e821020, p_current=0x2e8b5260, p_col=0, p_prev=0x0, r_in_range=0x0, p_force_deselect=false) at ./scene/gui/tree.cpp:2844
#14 0x000000000a22df01 in Tree::select_single_item (this=0x1569dbf0, p_selected=0x2e821020, p_current=0x2e9cc680, p_col=0, p_prev=0x0, r_in_range=0x0, p_force_deselect=false) at ./scene/gui/tree.cpp:2844
#15 0x000000000a238f35 in Tree::item_selected (this=0x1569dbf0, p_column=0, p_item=0x2e821020) at ./scene/gui/tree.cpp:4721
#16 0x000000000a218d9b in TreeItem::_cell_selected (this=0x2e821020, p_cell=0) at ./scene/gui/tree.cpp:91
#17 0x000000000a21f100 in TreeItem::select (this=0x2e821020, p_column=0) at ./scene/gui/tree.cpp:1253
#18 0x0000000008e18c05 in CreateDialog::select_type (this=0x15628d30, p_type=..., p_center_on_item=true) at ./editor/create_dialog.cpp:514
#19 0x0000000008e162dc in CreateDialog::_update_search (this=0x15628d30) at ./editor/create_dialog.cpp:239
--Type <RET> for more, q to quit, c to continue without paging--
#20 0x0000000008e182b2 in CreateDialog::_text_changed (this=0x15628d30, p_newtext=...) at ./editor/create_dialog.cpp:457
#21 0x000000000906e5d7 in call_with_variant_args_helper<CreateDialog, String const&, 0ul> (p_instance=0x15628d30, 
    p_method=(void (CreateDialog::*)(CreateDialog * const, const String &)) 0x8e18296 <CreateDialog::_text_changed(String const&)>, p_args=0x7fffffffca20, r_error=...) at ./core/variant/binder_common.h:315
#22 0x000000000905c54b in call_with_variant_args<CreateDialog, String const&> (p_instance=0x15628d30, 
    p_method=(void (CreateDialog::*)(CreateDialog * const, const String &)) 0x8e18296 <CreateDialog::_text_changed(String const&)>, p_args=0x7fffffffca20, p_argcount=1, r_error=...)
    at ./core/variant/binder_common.h:429
#23 0x000000000903870a in CallableCustomMethodPointer<CreateDialog, void, String const&>::call (this=0x15691e80, p_arguments=0x7fffffffca20, p_argcount=1, r_return_value=..., r_call_error=...)
    at ./core/object/callable_method_pointer.h:105
#24 0x000000000c15f603 in Callable::callp (this=0x7fffffffc840, p_arguments=0x7fffffffca20, p_argcount=1, r_return_value=..., r_call_error=...) at ./core/variant/callable.cpp:57
#25 0x000000000c4b175f in Object::emit_signalp (this=0x1568f570, p_name=..., p_args=0x7fffffffca20, p_argcount=1) at ./core/object/object.cpp:1236
#26 0x0000000009ec779e in Node::emit_signalp (this=0x1568f570, p_name=..., p_args=0x7fffffffca20, p_argcount=1) at ./scene/main/node.cpp:4021
#27 0x0000000008526716 in Object::emit_signal<String> (this=0x1568f570, p_name=...) at ./core/object/object.h:933
#28 0x000000000a117b1f in LineEdit::_emit_text_change (this=0x1568f570) at ./scene/gui/line_edit.cpp:2578
#29 0x000000000a117ac6 in LineEdit::_text_changed (this=0x1568f570) at ./scene/gui/line_edit.cpp:2573
#30 0x00000000090716ea in call_with_variant_args_helper<LineEdit>(LineEdit*, void (LineEdit::*)(), Variant const**, Callable::CallError&, IndexSequence<>) (p_instance=0x1568f570, 
    p_method=(void (LineEdit::*)(LineEdit * const)) 0xa117aae <LineEdit::_text_changed()>, p_args=0x0, r_error=...) at ./core/variant/binder_common.h:315
#31 0x000000000905ecd2 in call_with_variant_args<LineEdit> (p_instance=0x1568f570, p_method=(void (LineEdit::*)(LineEdit * const)) 0xa117aae <LineEdit::_text_changed()>, p_args=0x0, p_argcount=0, r_error=...)
    at ./core/variant/binder_common.h:429
#32 0x000000000904bf82 in CallableCustomMethodPointer<LineEdit, void>::call (this=0x2ea95b30, p_arguments=0x0, p_argcount=0, r_return_value=..., r_call_error=...) at ./core/object/callable_method_pointer.h:105
#33 0x000000000c15f603 in Callable::callp (this=0xe3d8a68, p_arguments=0x0, p_argcount=0, r_return_value=..., r_call_error=...) at ./core/variant/callable.cpp:57
#34 0x000000000c4a9f7b in CallQueue::_call_function (this=0xd0edec0, p_callable=..., p_args=0xe3d8a80, p_argcount=0, p_show_error=true) at ./core/object/message_queue.cpp:220
#35 0x000000000c4aa310 in CallQueue::flush (this=0xd0edec0) at ./core/object/message_queue.cpp:268
#36 0x0000000009ecb472 in SceneTree::process (this=0xf0599c0, p_time=0.004857083324284828) at ./scene/main/scene_tree.cpp:579
#37 0x0000000006caba6c in Main::iteration () at main/main.cpp:4496
--Type <RET> for more, q to quit, c to continue without paging--
#38 0x0000000006be346a in OS_LinuxBSD::run (this=0x7fffffffd130) at platform/linuxbsd/os_linuxbsd.cpp:962
#39 0x0000000006bdbbb1 in main (argc=2, argv=0x7fffffffd798) at platform/linuxbsd/godot_linuxbsd.cpp:85
```
Some more info:

```cpp
3701                                    const HashMap<String, DocData::ClassDoc> &class_list = EditorHelp::get_doc_data()->class_list;
3702                                    const DocData::ClassDoc *class_doc = class_list.getptr(symbol_class_name);
3703                                    String inherits = class_doc ? class_doc->inherits : String();
3704
3705                                    if (!inherits.is_empty()) {
3706                                            title->push_font(doc_source);
3707                                            title->push_font_size(doc_source_size * 0.9);
3708
3709                                            while (!inherits.is_empty()) {
3710                                                    title->push_color(symbol_color);
3711                                                    title->add_text(" <" + nbsp);
3712                                                    title->pop(); // color
3713
3714                                                    _add_type_to_title({ inherits, String(), false });
3715
3716                                                    inherits = class_list[inherits].inherits; // Crash here.
3717                                            }
3718
3719                                            title->pop(); // font_size
3720                                            title->pop(); // font
3721                                    }
```

```
(gdb) frame 1
#1  0x0000000008ec27da in EditorHelpBit::_update_labels (this=0x156d4f60) at ./editor/editor_help.cpp:3716
3716                                                    inherits = class_list[inherits].inherits;
(gdb) print inherits
$1 = {_cowdata = {static MAX_INT = <optimized out>, static REF_COUNT_OFFSET = <optimized out>, static SIZE_OFFSET = <optimized out>, static DATA_OFFSET = <optimized out>, _ptr = 0xeed1dd0 U"MyTool"}, 
  static _null = 0 U'\000', static _replacement_char = 65533 U'�'}
(gdb) print symbol_class_name
$2 = {_cowdata = {static MAX_INT = <optimized out>, static REF_COUNT_OFFSET = <optimized out>, static SIZE_OFFSET = <optimized out>, static DATA_OFFSET = <optimized out>, _ptr = 0x2e8ceb30 U"Test99"}, 
  static _null = 0 U'\000', static _replacement_char = 65533 U'�'}
(gdb) print class_doc->inherits
$3 = {_cowdata = {static MAX_INT = <optimized out>, static REF_COUNT_OFFSET = <optimized out>, static SIZE_OFFSET = <optimized out>, static DATA_OFFSET = <optimized out>, _ptr = 0xeed1dd0 U"MyTool"}, 
  static _null = 0 U'\000', static _replacement_char = 65533 U'�'}
(gdb) print class_list.getptr(inherits)
$4 = (const DocData::ClassDoc *) 0x0
(gdb) print class_list.getptr(symbol_class_name)
$5 = (const DocData::ClassDoc *) 0x29d64278
```

So surprisingly it's not `Test99` (the new `class_name` I used in my test to trigger the bug) which isn't found in available classes, but the `MyTool` it inherits, which I didn't modify. So somehow modifying the inheriting named class invalidates the class it inherits.

We can easily workaround the crash by just not dereferencing a nullptr, but the above might warrant further investigation as it sounds weird. For now I'll PR the workaround to fix the crash.
I can't reproduce it, but I would guess the error is here:

https://github.com/godotengine/godot/blob/5da6deaaca27f3d4ec5281d5b791408570919f15/editor/editor_help.cpp#L3716

This code assumes that if the class documentation specifies a parent class, then it exists. I had some doubts about this, but I left it unchecked, since I copied it from here:

https://github.com/godotengine/godot/blob/5da6deaaca27f3d4ec5281d5b791408570919f15/editor/editor_help.cpp#L1020

P.S. Akien confirmed it above.

Fix patch:
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index a577098168d4..0b6e817754e6 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1017,7 +1017,8 @@ void EditorHelp::_update_doc() {
 			class_desc->add_text(nbsp); // Otherwise icon borrows hyperlink from `_add_type()`.
 			_add_type(inherits);
 
-			inherits = doc->class_list[inherits].inherits;
+			const DocData::ClassDoc *base_class_doc = doc->class_list.getptr(inherits);
+			inherits = base_class_doc ? base_class_doc->inherits : String();
 
 			if (!inherits.is_empty()) {
 				class_desc->add_text(" < ");
@@ -3713,7 +3714,8 @@ void EditorHelpBit::_update_labels() {
 
 						_add_type_to_title({ inherits, String(), false });
 
-						inherits = class_list[inherits].inherits;
+						const DocData::ClassDoc *base_class_doc = class_list.getptr(inherits);
+						inherits = base_class_doc ? base_class_doc->inherits : String();
 					}
 
 					title->pop(); // font_size


Test patch: