godotengine / godot

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

Cutting with multiple cursors in TextEdit can crash in some cases. #85629

Closed kitbdev closed 11 months ago

kitbdev commented 11 months ago

Godot version

4.2, probably since #69102

System information

Godot v4.3.dev (d76c1d0e5) - Windows 10.0.22621 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 (NVIDIA; 31.0.15.3598) - Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz (12 Threads)

Issue description

When cutting in TextEdit with multiple carets, a crash can occur.

This happens because in TextEdit::_cut_internal the column gets set before the line is deleted, so the column index becomes out of range.

Debugger Log:

ERROR: FATAL: Index p_index = 14 is out of bounds (size() = 10).
master-godot.windows.editor.dev.x86_64.exe!CowData<char32_t>::get(int p_index) Line 158 (c:\Projects\godotsrc\godot\core\templates\cowdata.h:158)
master-godot.windows.editor.dev.x86_64.exe!String::operator[](int p_index) Line 226 (c:\Projects\godotsrc\godot\core\string\ustring.h:226)
master-godot.windows.editor.dev.x86_64.exe!TextEdit::_notification(int p_what) Line 624 (c:\Projects\godotsrc\godot\scene\gui\text_edit.cpp:624)
master-godot.windows.editor.dev.x86_64.exe!TextEdit::_notificationv(int p_notification, bool p_reversed) Line 42 (c:\Projects\godotsrc\godot\scene\gui\text_edit.h:42)
master-godot.windows.editor.dev.x86_64.exe!CodeEdit::_notificationv(int p_notification, bool p_reversed) Line 38 (c:\Projects\godotsrc\godot\scene\gui\code_edit.h:38)
master-godot.windows.editor.dev.x86_64.exe!Object::notification(int p_notification, bool p_reversed) Line 840 (c:\Projects\godotsrc\godot\core\object\object.cpp:840)
master-godot.windows.editor.dev.x86_64.exe!CanvasItem::_redraw_callback() Line 141 (c:\Projects\godotsrc\godot\scene\main\canvas_item.cpp:141)
master-godot.windows.editor.dev.x86_64.exe!call_with_variant_args_helper<CanvasItem>(CanvasItem * p_instance, void(CanvasItem::*)() p_method, const Variant * * p_args, Callable::CallError & r_error, IndexSequence<> __formal) Line 308 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:308)
master-godot.windows.editor.dev.x86_64.exe!call_with_variant_args<CanvasItem>(CanvasItem * p_instance, void(CanvasItem::*)() p_method, const Variant * * p_args, int p_argcount, Callable::CallError & r_error) Line 418 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:418)
master-godot.windows.editor.dev.x86_64.exe!CallableCustomMethodPointer<CanvasItem>::call(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) Line 99 (c:\Projects\godotsrc\godot\core\object\callable_method_pointer.h:99)
master-godot.windows.editor.dev.x86_64.exe!Callable::callp(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) Line 58 (c:\Projects\godotsrc\godot\core\variant\callable.cpp:58)
master-godot.windows.editor.dev.x86_64.exe!CallQueue::_call_function(const Callable & p_callable, const Variant * p_args, int p_argcount, bool p_show_error) Line 220 (c:\Projects\godotsrc\godot\core\object\message_queue.cpp:220)
master-godot.windows.editor.dev.x86_64.exe!CallQueue::flush() Line 326 (c:\Projects\godotsrc\godot\core\object\message_queue.cpp:326)
master-godot.windows.editor.dev.x86_64.exe!SceneTree::physics_process(double p_time) Line 473 (c:\Projects\godotsrc\godot\scene\main\scene_tree.cpp:473)
master-godot.windows.editor.dev.x86_64.exe!Main::iteration() Line 3598 (c:\Projects\godotsrc\godot\main\main.cpp:3598)
master-godot.windows.editor.dev.x86_64.exe!OS_Windows::run() Line 1474 (c:\Projects\godotsrc\godot\platform\windows\os_windows.cpp:1474)
master-godot.windows.editor.dev.x86_64.exe!widechar_main(int argc, wchar_t * * argv) Line 182 (c:\Projects\godotsrc\godot\platform\windows\godot_windows.cpp:182)
master-godot.windows.editor.dev.x86_64.exe!_main() Line 204 (c:\Projects\godotsrc\godot\platform\windows\godot_windows.cpp:204)
master-godot.windows.editor.dev.x86_64.exe!main(int argc, char * * argv) Line 218 (c:\Projects\godotsrc\godot\platform\windows\godot_windows.cpp:218)
master-godot.windows.editor.dev.x86_64.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) Line 232 (c:\Projects\godotsrc\godot\platform\windows\godot_windows.cpp:232)

related: #73202

81331 Doesn't stop the crash since instead it will happen at:

godot.windows.editor.dev.x86_64.exe!CowData<char32_t>::get(int p_index) Line 158 (c:\Projects\godotsrc\godot\core\templates\cowdata.h:158)
godot.windows.editor.dev.x86_64.exe!CharProxy<char32_t>::operator char32_t() Line 70 (c:\Projects\godotsrc\godot\core\string\ustring.h:70)
godot.windows.editor.dev.x86_64.exe!CodeTextEditor::_line_col_changed() Line 889 (c:\Projects\godotsrc\godot\editor\code_editor.cpp:889)
godot.windows.editor.dev.x86_64.exe!call_with_variant_args_helper<CodeTextEditor>(CodeTextEditor * p_instance, void(CodeTextEditor::*)() p_method, const Variant * * p_args, Callable::CallError & r_error, IndexSequence<> __formal) Line 308 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:308)
godot.windows.editor.dev.x86_64.exe!call_with_variant_args<CodeTextEditor>(CodeTextEditor * p_instance, void(CodeTextEditor::*)() p_method, const Variant * * p_args, int p_argcount, Callable::CallError & r_error) Line 418 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:418)
godot.windows.editor.dev.x86_64.exe!CallableCustomMethodPointer<CodeTextEditor>::call(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) Line 99 (c:\Projects\godotsrc\godot\core\object\callable_method_pointer.h:99)
godot.windows.editor.dev.x86_64.exe!Callable::callp(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) Line 58 (c:\Projects\godotsrc\godot\core\variant\callable.cpp:58)
godot.windows.editor.dev.x86_64.exe!Object::emit_signalp(const StringName & p_name, const Variant * * p_args, int p_argcount) Line 1128 (c:\Projects\godotsrc\godot\core\object\object.cpp:1128)
godot.windows.editor.dev.x86_64.exe!Node::emit_signalp(const StringName & p_name, const Variant * * p_args, int p_argcount) Line 3607 (c:\Projects\godotsrc\godot\scene\main\node.cpp:3607)
godot.windows.editor.dev.x86_64.exe!Object::emit_signal<>(const StringName & p_name) Line 922 (c:\Projects\godotsrc\godot\core\object\object.h:922)
godot.windows.editor.dev.x86_64.exe!TextEdit::_emit_caret_changed() Line 7073 (c:\Projects\godotsrc\godot\scene\gui\text_edit.cpp:7073)
godot.windows.editor.dev.x86_64.exe!call_with_variant_args_helper<TextEdit>(TextEdit * p_instance, void(TextEdit::*)() p_method, const Variant * * p_args, Callable::CallError & r_error, IndexSequence<> __formal) Line 308 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:308)
godot.windows.editor.dev.x86_64.exe!call_with_variant_args_dv<TextEdit>(TextEdit * p_instance, void(TextEdit::*)() p_method, const Variant * * p_args, int p_argcount, Callable::CallError & r_error, const Vector<Variant> & default_values) Line 451 (c:\Projects\godotsrc\godot\core\variant\binder_common.h:451)
godot.windows.editor.dev.x86_64.exe!MethodBindT<TextEdit>::call(Object * p_object, const Variant * * p_args, int p_arg_count, Callable::CallError & r_error) Line 337 (c:\Projects\godotsrc\godot\core\object\method_bind.h:337)
godot.windows.editor.dev.x86_64.exe!Object::callp(const StringName & p_method, const Variant * * p_args, int p_argcount, Callable::CallError & r_error) Line 775 (c:\Projects\godotsrc\godot\core\object\object.cpp:775)
godot.windows.editor.dev.x86_64.exe!Callable::callp(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) Line 69 (c:\Projects\godotsrc\godot\core\variant\callable.cpp:69)
godot.windows.editor.dev.x86_64.exe!CallQueue::_call_function(const Callable & p_callable, const Variant * p_args, int p_argcount, bool p_show_error) Line 220 (c:\Projects\godotsrc\godot\core\object\message_queue.cpp:220)
godot.windows.editor.dev.x86_64.exe!CallQueue::flush() Line 326 (c:\Projects\godotsrc\godot\core\object\message_queue.cpp:326)
godot.windows.editor.dev.x86_64.exe!SceneTree::physics_process(double p_time) Line 473 (c:\Projects\godotsrc\godot\scene\main\scene_tree.cpp:473)
godot.windows.editor.dev.x86_64.exe!Main::iteration() Line 3598 (c:\Projects\godotsrc\godot\main\main.cpp:3598)

I'm working on a PR that will fix the root cause of this and a number of other multicaret issues, but we may still want a smaller fix that can be easily cherrypicked.

Steps to reproduce

Steps:

  1. Make a script with at least 3 lines, the first two must be at least 3 characters longer than the third
  2. Put the first caret on the first line, at least 3 characters further right than where line 3 ends.
  3. Put the next caret on the second line
  4. auto_brace_completion_highlight_matching must be true (default for ScriptEditor)
  5. Hit ctrl+x or use the MenuBar Edit->Cut to cut the lines with a caret. (can't use context menu since it deselects other lines)
  6. The application should crash.

Cutting here will crash: image

Minimal reproduction project

N/A

kitbdev commented 11 months ago

Oops, looks like this is a duplicate of #81535