godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.57k stars 20.29k forks source link

When initializing a packed scene, if the packed scene root has a script that chooses a parent on _init(), causes errors and will cause segfault. #97525

Open OffsetMOSFET opened 2 days ago

OffsetMOSFET commented 2 days ago

Tested versions

4.3.1.rc

System information

Ubuntu 22.04.4 LTS 64-bit

Issue description

I have a class_name Foo that chooses its parent via a method of a Autoload/Singleton. Foo.new() works fine. However, if I have a load a packed scene whose root is Foo (load("foo.tscn")), trying to remove the child from the parent creates a "Children name does not match parent name in hashtable" error.

Closing the window via the [x] button / quit via the system context menu causes a segfault.

Freeing the object will silently crash.

ERROR: Children name does not match parent name in hashtable, this is a bug.
   at: remove_child (scene/main/node.cpp:1625)
Orphans:<Node3D#31423727074>
ERROR: Parameter "get_viewport()" is null.
   at: _notification (scene/main/node.cpp:144)
ERROR: Children name does not match parent name in hashtable, this is a bug.
   at: remove_child (scene/main/node.cpp:1625)
ERROR: Condition "data.parent" is true.
   at: ~Node (scene/main/node.cpp:3847)

================================================================
handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.3.1.rc.custom_build (ff9bc0422349219b337b015643544a0454d4a7ee)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib/x86_64-linux-gnu/libc.so.6(+0x42520) [0x7c8191a42520] (??:0)
[2] Object::notification(int, bool) (/home/leonard/Git/godot/core/object/object.cpp:884)
[3] Object::_predelete() (/home/leonard/Git/godot/core/object/object.cpp:199)
[4] predelete_handler(Object*) (/home/leonard/Git/godot/core/object/object.cpp:2125)
[5] void memdelete<Node>(Node*) (/home/leonard/Git/godot/./core/os/memory.h:112)
[6] Node::_notification(int) (/home/leonard/Git/godot/scene/main/node.cpp:245)
[7] Node::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/node.h:50 (discriminator 14))
[8] Node3D::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/3d/node_3d.h:52)
[9] Object::notification(int, bool) (/home/leonard/Git/godot/core/object/object.cpp:890)
[10] Object::_predelete() (/home/leonard/Git/godot/core/object/object.cpp:199)
[11] predelete_handler(Object*) (/home/leonard/Git/godot/core/object/object.cpp:2125)
[12] void memdelete<Node>(Node*) (/home/leonard/Git/godot/./core/os/memory.h:112)
[13] Node::_notification(int) (/home/leonard/Git/godot/scene/main/node.cpp:245)
[14] Node::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/node.h:50 (discriminator 14))
[15] CanvasItem::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/canvas_item.h:45)
[16] Control::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/gui/control.h:48)
[17] Object::notification(int, bool) (/home/leonard/Git/godot/core/object/object.cpp:890)
[18] Object::_predelete() (/home/leonard/Git/godot/core/object/object.cpp:199)
[19] predelete_handler(Object*) (/home/leonard/Git/godot/core/object/object.cpp:2125)
[20] void memdelete<Node>(Node*) (/home/leonard/Git/godot/./core/os/memory.h:112)
[21] Node::_notification(int) (/home/leonard/Git/godot/scene/main/node.cpp:245)
[22] Node::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/node.h:50 (discriminator 14))
[23] Viewport::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/viewport.h:95)
[24] Window::_notificationv(int, bool) (/home/leonard/Git/godot/./scene/main/window.h:44)
[25] Object::notification(int, bool) (/home/leonard/Git/godot/core/object/object.cpp:890)
[26] Object::_predelete() (/home/leonard/Git/godot/core/object/object.cpp:199)
[27] predelete_handler(Object*) (/home/leonard/Git/godot/core/object/object.cpp:2125)
[28] void memdelete<Window>(Window*) (/home/leonard/Git/godot/./core/os/memory.h:112)
[29] SceneTree::finalize() (/home/leonard/Git/godot/scene/main/scene_tree.cpp:645)
[30] OS_LinuxBSD::run() (/home/leonard/Git/godot/platform/linuxbsd/os_linuxbsd.cpp:967)
[31] /home/leonard/Git/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x190) [0x5f09e01af539] (/home/leonard/Git/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[32] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7c8191a29d90] (??:0)
[33] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7c8191a29e40] (??:0)
[34] /home/leonard/Git/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5f09e01af2e5] (??:?)
-- END OF BACKTRACE --
================================================================

Steps to reproduce

I have attached an MRP.

The class_name Foo accesses a singleton to be able to be added to the tree. The main script will load a packedscene of Foo on ready, which is when the issues should start.

Minimal reproduction project (MRP)

parent_crash.zip

matheusmdx commented 1 day ago

Bisecting points to #75627 as the culprit, @reduz

Captura 2024-09-27 07-46-31-261992


Errors + backtrace in vscode ``` ERROR: Children name does not match parent name in hashtable, this is a bug. at: (scene\main\node.cpp:1199) Children name does not match parent name in hashtable, this is a bug. Orphans: ERROR: Condition "!get_viewport()" is true. at: Node::_notification (scene\main\node.cpp:98) scene\main\node.cpp:98 - Condition "!get_viewport()" is true. ERROR: Children name does not match parent name in hashtable, this is a bug. at: (scene\main\node.cpp:1199) Children name does not match parent name in hashtable, this is a bug. ERROR: Condition "data.parent" is true. at: Node::~Node (scene\main\node.cpp:3086) scene\main\node.cpp:3086 - Condition "data.parent" is true. Critical error detected c0000374 ntdll.dll!00007ffbe08af3c2() (Unknown Source:0) ntdll.dll!00007ffbe08b8182() (Unknown Source:0) ntdll.dll!00007ffbe08b846a() (Unknown Source:0) ntdll.dll!00007ffbe08be0f1() (Unknown Source:0) ntdll.dll!00007ffbe07d5bf0() (Unknown Source:0) ntdll.dll!00007ffbe07d47b1() (Unknown Source:0) AcLayers.dll!00007ffb73278931() (Unknown Source:0) _free_base(void * block) Line 105 (c:\Users\Matheus\AppData\Local\Programs\Microsoft VS Code\minkernel\crts\ucrt\src\appcrt\heap\free_base.cpp:105) Memory::free_static(void * p_ptr, bool p_pad_align) Line 169 (c:\Users\Matheus\Downloads\Godot Source\core\os\memory.cpp:169) memdelete(Node * p_class) Line 113 (c:\Users\Matheus\Downloads\Godot Source\core\os\memory.h:113) Node::_notification(int p_notification) Line 171 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.cpp:171) Node::_notificationv(int p_notification, bool p_reversed) Line 46 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.h:46) Node3D::_notificationv(int p_notification, bool p_reversed) Line 52 (c:\Users\Matheus\Downloads\Godot Source\scene\3d\node_3d.h:52) Object::notification(int p_notification, bool p_reversed) Line 792 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:792) Object::_predelete() Line 197 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:197) predelete_handler(Object * p_object) Line 1836 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:1836) memdelete(Node * p_class) Line 105 (c:\Users\Matheus\Downloads\Godot Source\core\os\memory.h:105) Node::_notification(int p_notification) Line 171 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.cpp:171) Node::_notificationv(int p_notification, bool p_reversed) Line 46 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.h:46) CanvasItem::_notificationv(int p_notification, bool p_reversed) Line 45 (c:\Users\Matheus\Downloads\Godot Source\scene\main\canvas_item.h:45) Control::_notificationv(int p_notification, bool p_reversed) Line 47 (c:\Users\Matheus\Downloads\Godot Source\scene\gui\control.h:47) Object::notification(int p_notification, bool p_reversed) Line 792 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:792) Object::_predelete() Line 197 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:197) predelete_handler(Object * p_object) Line 1836 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:1836) memdelete(Node * p_class) Line 105 (c:\Users\Matheus\Downloads\Godot Source\core\os\memory.h:105) Node::_notification(int p_notification) Line 171 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.cpp:171) Node::_notificationv(int p_notification, bool p_reversed) Line 46 (c:\Users\Matheus\Downloads\Godot Source\scene\main\node.h:46) Viewport::_notificationv(int p_notification, bool p_reversed) Line 89 (c:\Users\Matheus\Downloads\Godot Source\scene\main\viewport.h:89) Window::_notificationv(int p_notification, bool p_reversed) Line 44 (c:\Users\Matheus\Downloads\Godot Source\scene\main\window.h:44) Object::notification(int p_notification, bool p_reversed) Line 792 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:792) Object::_predelete() Line 197 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:197) predelete_handler(Object * p_object) Line 1836 (c:\Users\Matheus\Downloads\Godot Source\core\object\object.cpp:1836) memdelete(Window * p_class) Line 105 (c:\Users\Matheus\Downloads\Godot Source\core\os\memory.h:105) SceneTree::finalize() Line 585 (c:\Users\Matheus\Downloads\Godot Source\scene\main\scene_tree.cpp:585) OS_Windows::run() Line 1306 (c:\Users\Matheus\Downloads\Godot Source\platform\windows\os_windows.cpp:1306) widechar_main(int argc, wchar_t * * argv) Line 181 (c:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:181) _main() Line 203 (c:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:203) main(int argc, char * * argv) Line 217 (c:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:217) WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) Line 231 (c:\Users\Matheus\Downloads\Godot Source\platform\windows\godot_windows.cpp:231) [Inline Frame] invoke_main() Line 102 (d:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:102) __scrt_common_main_seh() Line 288 (d:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288) kernel32.dll!00007ffbdff37374() (Unknown Source:0) ntdll.dll!00007ffbe07fcc91() (Unknown Source:0) ```
AtlaStar commented 1 day ago

Went ahead and tested the results when there was a failure to find the child. It appears that it is saving the node with an autogenerated name rather than Foo on the Orphan node.

image First value is the StringName of the hashmap data.children, second value is the name of the Node pointer in the hashmap data.children and the third value is the name of the node passed into the remove_child function.

Creating the node using new on the packed scene causes the scene to be named @Node@2 and save itself as a Node type rather than the Node3d type as in the scene itself.

From what I have tested, inside of _init the scene is yet to have a name, but using instantiate will eventually set the name to the root node name, while new does not. Setting the name to Foo inside of _init will make the instantiate method of constructing work without crashing, as well as working with the new method of constructing the packed scene.

Not as familiar with the API yet, so unsure of the best solution, but it would seem that having the packed scene set its name early on or blocking other threads of execution until the name is set would be the "proper" fix.

EDIT: Might actually be in Node thinking on it more...still not sure where or when names are typically assigned