Skip to content

Use-after-free of popup_pressing_edited_item when modifying tree items #107774

@a-johnston

Description

@a-johnston

Tested versions

Tested on 4.5-beta, 4.4.1-stable macos and linux

System information

Godot v4.5.beta.mono (5abed52) - macOS Sequoia (15.5.0) - Multi-window, 1 monitor - Metal (Forward+) - integrated Apple M2 (Apple8) - Apple M2 (8 threads) - 24.00 GiB memory

Issue description

In some cases, tree items can be disconnected from their tree while set as popup_pressing_edited_item. Since they only check popup_edited_item when being disconnected, this tree field does not get cleared and that can result in a crash on subsequent uses of popup_pressing_edited_item:

handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.4.1.stable.custom_build (49a5bc7b616bd04689a2c89e89bda41f50241464)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x19c30) [0x7fa3d07a1c30] (??:0)
[2] CowData<TreeItem::Cell>::size() const (/home/<user>/Documents/godot_custom/godot/./core/templates/cowdata.h:197)
[3] Vector<TreeItem::Cell>::size() const (/home/<user>/Documents/godot_custom/godot/./core/templates/vector.h:99)
[4] TreeItem::get_cell_mode(int) const (/home/<user>/Documents/godot_custom/godot/scene/gui/tree.cpp:184 (discriminator 4))
[5] Tree::gui_input(Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/scene/gui/tree.cpp:3693 (discriminator 8))
[6] Control::_call_gui_input(Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/scene/gui/control.cpp:1825)
[7] Viewport::_gui_call_input(Control*, Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/scene/main/viewport.cpp:1636)
[8] Viewport::_gui_input_event(Ref<InputEvent>) (/home/<user>/Documents/godot_custom/godot/scene/main/viewport.cpp:2046 (discriminator 2))
[9] Viewport::push_input(Ref<InputEvent> const&, bool) (/home/<user>/Documents/godot_custom/godot/scene/main/viewport.cpp:3291 (discriminator 2))
[10] Window::_window_input(Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/scene/main/window.cpp:1703)
[11] void call_with_variant_args_helper<Window, Ref<InputEvent> const&, 0ul>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, Callable::CallError&, IndexSequence<0ul>) (/home/<user>/Documents/godot_custom/godot/./core/variant/binder_common.h:315 (discriminator 6))
[12] void call_with_variant_args<Window, Ref<InputEvent> const&>(Window*, void (Window::*)(Ref<InputEvent> const&), Variant const**, int, Callable::CallError&) (/home/<user>/Documents/godot_custom/godot/./core/variant/binder_common.h:430)
[13] CallableCustomMethodPointer<Window, void, Ref<InputEvent> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const (/home/<user>/Documents/godot_custom/godot/./core/object/callable_method_pointer.h:109)
[14] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/home/<user>/Documents/godot_custom/godot/core/variant/callable.cpp:57)
[15] Variant Callable::call<Ref<InputEvent> >(Ref<InputEvent>) const (/home/<user>/Documents/godot_custom/godot/./core/variant/variant.h:952)
[16] DisplayServerX11::_dispatch_input_event(Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/platform/linuxbsd/x11/display_server_x11.cpp:4261 (discriminator 2))
[17] DisplayServerX11::_dispatch_input_events(Ref<InputEvent> const&) (/home/<user>/Documents/godot_custom/godot/platform/linuxbsd/x11/display_server_x11.cpp:4238)
[18] Input::_parse_input_event_impl(Ref<InputEvent> const&, bool) (/home/<user>/Documents/godot_custom/godot/core/input/input.cpp:905)
[19] Input::flush_buffered_events() (/home/<user>/Documents/godot_custom/godot/core/input/input.cpp:1186)
[20] DisplayServerX11::process_events() (/home/<user>/Documents/godot_custom/godot/platform/linuxbsd/x11/display_server_x11.cpp:5403)
[21] OS_LinuxBSD::run() (/home/<user>/Documents/godot_custom/godot/platform/linuxbsd/os_linuxbsd.cpp:978)
[22] /home/<user>/Documents/godot_custom/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x14b) [0x406a01] (/home/<user>/Documents/godot_custom/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[23] /lib64/libc.so.6(+0x35f5) [0x7fa3d078b5f5] (??:0)
[24] /lib64/libc.so.6(__libc_start_main+0x88) [0x7fa3d078b6a8] (??:0)
[25] /home/<user>/Documents/godot_custom/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x4067f5] (??:?)
-- END OF BACKTRACE --

when testing on macos, the address would be marked as freed but not recovered by the os so it wouldn't crash outright but would report as freed.

Steps to reproduce

This was tested in https://github.com/mich-gamedev/togodoo

  1. optionally, add a print/check prior to this line to see the value of popup_pressing_edited_item
  2. run scenes/main_refactor/main.tscn
  3. aggressively drag and drop to reorder tree items on the left until the random crash happens (there may be a more consistent trigger but this is what worked for me)

Minimal reproduction project (MRP)

no mrp but the scene scenes/main_refactor/main.tscn in https://github.com/mich-gamedev/togodoo (60aa24a0d7a8515bb5830e) was used for testing

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions