Repository: godotengine/godot (language: cpp)

Issue:
Segfault in `SceneTreeEditor::NodeCache::mark_dirty`
### Tested versions

4.4.dev (2582793d408ade0b6ed42f913ae33e7da5fb9184)

### System information

Arch Linux 6.12.6, Ryzen 3600, RX 6700XT

### Issue description

Godot crashes
```
================================================================
handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.4.dev.custom_build (2582793d408ade0b6ed42f913ae33e7da5fb9184)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /usr/lib/libc.so.6(+0x3d1d0) [0x7e3853a501d0] (??:0)
[2] Node::get_parent() const (/mnt/data-drive/code/downloads/godot/scene/main/node.cpp:2002)
[3] SceneTreeEditor::NodeCache::mark_dirty(Node*, bool) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:2282 (discriminator 1))
[4] SceneTreeEditor::_update_marking_list(HashSet<Node*, HashMapHasherDefault, HashMapComparatorDefault<Node*> > const&) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:1509)
[5] SceneTreeEditor::set_marked(HashSet<Node*, HashMapHasherDefault, HashMapComparatorDefault<Node*> > const&, bool, bool) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:1518)
[6] SceneTreeEditor::set_marked(Node*, bool, bool) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:1533)
[7] SceneTreeDialog::popup_scenetree_dialog(Node*, Node*, bool, bool) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:2013)
[8] AnimationTrackEditor::_add_track(int) (/mnt/data-drive/code/downloads/godot/editor/animation_track_editor.cpp:5359)
[9] void call_with_variant_args_helper<AnimationTrackEditor, int, 0ul>(AnimationTrackEditor*, void (AnimationTrackEditor::*)(int), Variant const**, Callable::CallError&, IndexSequence<0ul>) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:308)
[10] void call_with_variant_args<AnimationTrackEditor, int>(AnimationTrackEditor*, void (AnimationTrackEditor::*)(int), Variant const**, int, Callable::CallError&) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:418)
[11] CallableCustomMethodPointer<AnimationTrackEditor, void, int>::call(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/./core/object/callable_method_pointer.h:109)
[12] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/core/variant/callable.cpp:57)
[13] Object::emit_signalp(StringName const&, Variant const**, int) (/mnt/data-drive/code/downloads/godot/core/object/object.cpp:1200)
[14] Node::emit_signalp(StringName const&, Variant const**, int) (/mnt/data-drive/code/downloads/godot/scene/main/node.cpp:4021)
[15] Error Object::emit_signal<int>(StringName const&, int) (/mnt/data-drive/code/downloads/godot/./core/object/object.h:922)
[16] AnimationTimelineEdit::_track_added(int) (/mnt/data-drive/code/downloads/godot/editor/animation_track_editor.cpp:1978)
[17] void call_with_variant_args_helper<AnimationTimelineEdit, int, 0ul>(AnimationTimelineEdit*, void (AnimationTimelineEdit::*)(int), Variant const**, Callable::CallError&, IndexSequence<0ul>) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:308)
[18] void call_with_variant_args<AnimationTimelineEdit, int>(AnimationTimelineEdit*, void (AnimationTimelineEdit::*)(int), Variant const**, int, Callable::CallError&) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:418)
[19] CallableCustomMethodPointer<AnimationTimelineEdit, void, int>::call(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/./core/object/callable_method_pointer.h:109)
[20] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/core/variant/callable.cpp:57)
[21] Object::emit_signalp(StringName const&, Variant const**, int) (/mnt/data-drive/code/downloads/godot/core/object/object.cpp:1200)
[22] Node::emit_signalp(StringName const&, Variant const**, int) (/mnt/data-drive/code/downloads/godot/scene/main/node.cpp:4021)
[23] Error Object::emit_signal<int>(StringName const&, int) (/mnt/data-drive/code/downloads/godot/./core/object/object.h:922)
[24] PopupMenu::activate_item(int) (/mnt/data-drive/code/downloads/godot/scene/gui/popup_menu.cpp:2437)
[25] PopupMenu::_input_from_window_internal(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/scene/gui/popup_menu.cpp:635)
[26] PopupMenu::_input_from_window(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/scene/gui/popup_menu.cpp:445)
[27] Window::_window_input(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/scene/main/window.cpp:1689)
[28] Viewport::_sub_windows_forward_input(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/scene/main/viewport.cpp:2956)
[29] Viewport::push_input(Ref<InputEvent> const&, bool) (/mnt/data-drive/code/downloads/godot/scene/main/viewport.cpp:3225 (discriminator 1))
[30] Window::_window_input(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/scene/main/window.cpp:1694)
[31] void call_with_variant_args_helper<Window, Ref<InputEvent> const&, 0ul>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, Callable::CallError&, IndexSequence<0ul>) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:303 (discriminator 2))
[32] void call_with_variant_args<Window, Ref<InputEvent> const&>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, int, Callable::CallError&) (/mnt/data-drive/code/downloads/godot/./core/variant/binder_common.h:418)
[33] CallableCustomMethodPointer<Window, void, Ref<InputEvent> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/./core/object/callable_method_pointer.h:109)
[34] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/mnt/data-drive/code/downloads/godot/core/variant/callable.cpp:57)
[35] Variant Callable::call<Ref<InputEvent> >(Ref<InputEvent>) const (/mnt/data-drive/code/downloads/godot/./core/variant/variant.h:912)
[36] DisplayServerWayland::_dispatch_input_event(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/platform/linuxbsd/wayland/display_server_wayland.cpp:95 (discriminator 2))
[37] DisplayServerWayland::dispatch_input_events(Ref<InputEvent> const&) (/mnt/data-drive/code/downloads/godot/platform/linuxbsd/wayland/display_server_wayland.cpp:90)
[38] Input::_parse_input_event_impl(Ref<InputEvent> const&, bool) (/mnt/data-drive/code/downloads/godot/core/input/input.cpp:922)
[39] Input::flush_buffered_events() (/mnt/data-drive/code/downloads/godot/core/input/input.cpp:1203)
[40] DisplayServerWayland::process_events() (/mnt/data-drive/code/downloads/godot/platform/linuxbsd/wayland/display_server_wayland.cpp:1259)
[41] OS_LinuxBSD::run() (/mnt/data-drive/code/downloads/godot/platform/linuxbsd/os_linuxbsd.cpp:960)
[42] /mnt/data-drive/code/downloads/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x18c) [0x5926cf9705d5] (/mnt/data-drive/code/downloads/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[43] /usr/lib/libc.so.6(+0x25e08) [0x7e3853a38e08] (??:0)
[44] /usr/lib/libc.so.6(__libc_start_main+0x8c) [0x7e3853a38ecc] (??:0)
[45] /mnt/data-drive/code/downloads/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5926cf970375] (??:?)
-- END OF BACKTRACE --
================================================================
```

### Steps to reproduce

Not sure. Happens randomly when you run the game

### Minimal reproduction project (MRP)

N/A


Discussion / hints:
~~Hard to say what this might be without an MRP given you seem to be running a custom build of Godot 4.4.~~
~~Where did you get this build of Godot from? And can you provide any info about where `get_parent()` is being called?~~
Scratch that - akien-mga figured it out
The crash happens in code added by 6f7525c396c, CC @hpvb.

Thread safety issue maybe?

```cpp
void SceneTreeEditor::NodeCache::mark_dirty(Node *p_node, bool p_parents) {
	Node *node = p_node;
	while (node) {
		HashMap<Node *, CachedNode>::Iterator I = cache.find(node);
		if (I) {
			I->value.dirty = true;
		}

		if (!p_parents) {
			break;
		}
		node = node->get_parent();
	}
}
```
Ah, no, it is because of `[4] SceneTreeEditor::_update_marking_list(HashSet<Node*, HashMapHasherDefault, HashMapComparatorDefault<Node*> > const&) (/mnt/data-drive/code/downloads/godot/editor/gui/scene_tree_editor.cpp:1509)`

What seems to happen is that the `marked` list isn't cleared when the scene changes. This is easy enough to fix. It's not a thread safety issue, none of this was ever thread safe, even before my changes.

Fix patch:
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index e5a7a53ffa7e..ae0276916b37 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -892,6 +892,15 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
 		return;
 	}
 
+	Node *scene_node = get_scene_node();
+
+	if (node_cache.current_scene_node != scene_node) {
+		_reset();
+		marked.clear();
+		node_cache.current_scene_node = scene_node;
+		node_cache.force_update = true;
+	}
+
 	if (!update_when_invisible && !is_visible_in_tree()) {
 		return;
 	}
@@ -903,13 +912,6 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
 	updating_tree = true;
 
 	last_hash = hash_djb2_one_64(0);
-	Node *scene_node = get_scene_node();
-
-	if (node_cache.current_scene_node != scene_node) {
-		_reset();
-		node_cache.current_scene_node = scene_node;
-		node_cache.force_update = true;
-	}
 
 	if (node_cache.current_scene_node) {
 		// Handle pinning/unpinning the animation player only do this once per iteration.


Test patch: