Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite loop in rich_text_label.cpp (ERROR: _process_line: Index line = 0 is out of bounds) #38058

Open
Tracked by #39144
DrMoriarty opened this issue Apr 20, 2020 · 33 comments

Comments

@DrMoriarty
Copy link
Contributor

DrMoriarty commented Apr 20, 2020


Bugsquad note: This issue has been confirmed several times already. No need to confirm it further.


Godot version:
Godot 3.2.2.beta1

OS/device including version:
MacOSX 10.14.6 (18G95)

Issue description:
Today all day I'm working on fixing pvrtc and twice my godot did hung up with this errors:

   At: scene/gui/rich_text_label.cpp:170.
ERROR: _process_line: Index line = 0 is out of bounds (l.offset_caches.size() = 0).
   At: scene/gui/rich_text_label.cpp:170.
ERROR: _process_line: Index line = 0 is out of bounds (l.offset_caches.size() = 0).
   At: scene/gui/rich_text_label.cpp:170.
ERROR: _process_line: Index line = 0 is out of bounds (l.offset_caches.size() = 0).
   At: scene/gui/rich_text_label.cpp:170.
ERROR: _process_line: Index line = 0 is out of bounds (l.offset_caches.size() = 0).

It repeats in infinite cycle and godot interface is frozen. I can not reproduce it when I want to. But two times it happened.

Steps to reproduce:

Minimal reproduction project:

@aaronfranke
Copy link
Member

This code is weird. line is guaranteed to be 0 here, so the check whether line is between 0 and the size should be simplified to just a check for if the size is 0. I don't know why it would be 0, though.

@Eoin-ONeill-Yokai
Copy link
Contributor

I haven't looked majorly into this, but I think that the caching system and this check might be what's returning garbage line size values as well. So I think this is possibly related to #18722. @DrMoriarty I haven't had a chance to reproduce this myself and can't find a way to reproduce it. If someone else can try getting a gdb trace on this, that'd be very useful.

For the record, as someone who has worked on this class within the last year (or two I suppose), the problem this class currently has is that the codeflow is hard to parse because of a combination of extensive macro-use and arguably too many vaguely named variables. It's kind of on my todo to go back to this class and clean it up to make it easier to work with, but I never really find the time.

line is guaranteed to be 0 here, so the check whether line is between 0 and the size should be simplified to just a check for if the size is 0.

@aaronfranke Indeed. I think there's a very high likelihood that these checks were actually intended for the macro define on line 216 and were but in the wrong place probably because the macro text is greyed out.

@HungryProton
Copy link
Contributor

Not sure if it's related but this issue consistently happens since I tried adding multi-threading to my addon. I'll see if I can produce a minimal reproduction project but the code is so convoluted I'm having a hard time tracking down this issue.

@BattyBovine
Copy link

Just wanted to confirm that I'm now getting this same error, every single time I push a build to my Android phone for debugging, and it seems to have started as soon as I started using ResourceInteractiveLoader to switch scenes. Removing that part of the code doesn't seem to have stopped this issue from happening every time I run the debugger, but disabling "Small Deploy with Network FS" seems to work. This also seems to only affect Android as far as I can tell, and not when I run a debug build on Windows 10.

@Calinou Calinou added this to the 4.0 milestone May 15, 2020
@lupoDharkael
Copy link
Contributor

I'm working on a C++ module and I'm having the same experience as @HungryProton. I do procedural generation from a thread and this happens sometimes when I use print_line(). The reproduction rate seems arbitrary.

@lupoDharkael
Copy link
Contributor

lupoDharkael commented May 22, 2020

@Eoin-ONeill-Yokai I have a trace from commit 561438c

GDB bt
#0  0x00007ffff76ef4bf in write () from /lib64/libc.so.6
#1  0x00007ffff767f4cd in _IO_file_write@@GLIBC_2.2.5 () from /lib64/libc.so.6
#2  0x00007ffff767e826 in new_do_write () from /lib64/libc.so.6
#3  0x00007ffff767fbfe in __GI__IO_file_xsputn () from /lib64/libc.so.6
#4  0x00007ffff766b6b1 in buffered_vfprintf () from /lib64/libc.so.6
#5  0x00007ffff7668654 in __vfprintf_internal () from /lib64/libc.so.6
#6  0x0000000006e549cd in StdLogger::logv (this=0x77d6750, p_format=0x1b21d10 "%sERROR:%s %s\n", 
    p_list=0x7fffffffab70, p_err=true) at core/io/logger.cpp:230
#7  0x0000000006e53901 in Logger::logf_error (this=0x77d6750, p_format=0x1b21d10 "%sERROR:%s %s\n")
    at core/io/logger.cpp:100
#8  0x00000000048b0543 in UnixTerminalLogger::log_error (this=0x77d6750, 
    p_function=0x1b453da "_process_line", p_file=0x1b453e8 "scene/gui/rich_text_label.cpp", p_line=176, 
    p_code=0x3a4cb630 "Index line = 0 is out of bounds (l.offset_caches.size() = 0).", 
    p_rationale=0x1b8389b "", p_type=Logger::ERR_ERROR) at drivers/unix/os_unix.cpp:582
#9  0x0000000006e54c59 in CompositeLogger::log_error (this=0x77d6790, 
    p_function=0x1b453da "_process_line", p_file=0x1b453e8 "scene/gui/rich_text_label.cpp", p_line=176, 
    p_code=0x3a4cb630 "Index line = 0 is out of bounds (l.offset_caches.size() = 0).", 
    p_rationale=0x1b8389b "", p_type=Logger::ERR_ERROR) at core/io/logger.cpp:264
#10 0x0000000006cac54a in OS::print_error (this=0x7fffffffd5e8, p_function=0x1b453da "_process_line", 
    p_file=0x1b453e8 "scene/gui/rich_text_label.cpp", p_line=176, 
    p_code=0x3a4cb630 "Index line = 0 is out of bounds (l.offset_caches.size() = 0).", 
    p_rationale=0x1b8389b "", p_type=Logger::ERR_ERROR) at core/os/os.cpp:120
#11 0x0000000006ab6e57 in _err_print_error (p_function=0x1b453da "_process_line", 
    p_file=0x1b453e8 "scene/gui/rich_text_label.cpp", p_line=176, 
    p_error=0x3a4cb630 "Index line = 0 is out of bounds (l.offset_caches.size() = 0).", 
    p_message=0x1b8389b "", p_type=ERR_HANDLER_ERROR) at core/error_macros.cpp:81
#12 0x0000000006ab7513 in _err_print_index_error (p_function=0x1b453da "_process_line", 
    p_file=0x1b453e8 "scene/gui/rich_text_label.cpp", p_line=176, p_index=0, p_size=0, 
    p_index_str=0x1a8d3f2 "line", p_size_str=0x1a18d15 "l.offset_caches.size()", p_message=0x1b8389b "", 
    fatal=false) at core/error_macros.cpp:110
#13 0x0000000005977a06 in RichTextLabel::_process_line (this=0xe7d23d0, p_frame=0xe7d2a90, p_ofs=..., 
    y=@0x7fffffffc91c: 172, p_width=1333, p_line=470075, p_mode=RichTextLabel::PROCESS_DRAW, 
    p_base_font=..., p_base_color=..., p_font_color_shadow=..., p_shadow_as_outline=false, 
    shadow_ofs=..., p_click_pos=..., r_click_item=0x0, r_click_char=0x0, r_outside=0x0, 
    p_char_count=18487) at scene/gui/rich_text_label.cpp:176
#14 0x00000000059818fe in RichTextLabel::_notification (this=0xe7d23d0, p_what=30)
    at scene/gui/rich_text_label.cpp:1039
#15 0x000000000599626b in RichTextLabel::_notificationv (this=0xe7d23d0, p_notification=30, 
    p_reversed=false) at scene/gui/rich_text_label.h:39
#16 0x0000000006b45a4b in Object::notification (this=0xe7d23d0, p_notification=30, p_reversed=false)
    at core/object.cpp:914
#17 0x00000000056d24d8 in CanvasItem::_update_callback (this=0xe7d23d0) at scene/main/canvas_item.cpp:452
#18 0x00000000056e7764 in MethodBind0::call (this=0x8acf450, p_object=0xe7d23d0, p_args=0x0, 
    p_arg_count=0, r_error=...) at ./core/method_bind.gen.inc:147
#19 0x0000000006b48f6a in Object::call (this=0xe7d23d0, p_method=..., p_args=0x0, p_argcount=0, 
    r_error=...) at core/object.cpp:904
#20 0x0000000006a86323 in Callable::call (this=0x7fffe9e31020, p_arguments=0x0, p_argcount=0, 
    r_return_value=..., r_call_error=...) at core/callable.cpp:52
#21 0x0000000006b3d043 in MessageQueue::_call_function (this=0x78d1990, p_callable=..., 
    p_args=0x7fffe9e31038, p_argcount=0, p_show_error=false) at core/message_queue.cpp:253
#22 0x0000000006b3d392 in MessageQueue::flush (this=0x78d1990) at core/message_queue.cpp:303
#23 0x000000000575cba5 in SceneTree::idle (this=0x911c180, p_time=0.020833334)
    at scene/main/scene_tree.cpp:460
#24 0x00000000035535b5 in Main::iteration () at main/main.cpp:2190
#25 0x00000000035168e6 in OS_LinuxBSD::run (this=0x7fffffffd5e8) at platform/linuxbsd/os_linuxbsd.cpp:259
#26 0x0000000003514276 in main (argc=4, argv=0x7fffffffdac8) at platform/linuxbsd/godot_linuxbsd.cpp:56

@ebeem
Copy link

ebeem commented May 24, 2020

I am using threads, and it's causing this issue to me.

I don't understand why it works sometimes, shouldn't we always update GUI from the main thread?
as a workaround, instead of updating the control immediately (richtext to store console/terminal logs in my case), I am storing the list of strings I want to add to my log.

I am actually wondering how it works sometimes anyway, I don't think we can update the GUI from a thread other than the main, it seems like there's something that handles such situations in Godot?

before

        private Node _console;
        private Node Console
        {
            get
            {
                if (_console == null)
                    _console = GetNode("/root/Console");
                return _console;
            }
        }
        public void WriteLine(string text)
        {
            Console.Call("writeLine", text);
        }
        
        public void Write(string text)
        {
            Console.Call("write", text);
        }

after

        private Node _console;
        private Queue<string> _logLines = new Queue<string>();
        private Queue<string> _logs = new Queue<string>();

        private Node Console
        {
            get
            {
                if (_console == null)
                    _console = GetNode("/root/Console");
                return _console;
            }
        }

        public void WriteLine(string text)
        {
            _logLines.Enqueue(text);
        }

        public void Write(string text)
        {
            _logs.Enqueue(text);
        }

        public override void _Process(float delta)
        {
            base._Process(delta);
            while(_logs.Count > 0)
                Console.Call("write", _logs.Dequeue());
            while(_logLines.Count > 0)
                Console.Call("writeLine", _logLines.Dequeue());
        }

@Rubonnek
Copy link
Member

This just started happening to me quite often in 3.2 branch at commit 49b3750.

I'm not explicitly using threads in GDScript land -- only the intrinsic threads the engine itself uses, and the threaded LSP server.

Here's the backtrace I was able to catch:

#0  RichTextLabel::_process_line (this=0xe6a7810, p_frame=0xe6a7f90, p_ofs=..., y=@0x7fffffffcec4: 0, p_width=-8, p_line=0, p_mode=RichTextLabel::PROCESS_DRAW, p_base_font=..., p_base_color=..., p_font_color_shadow=..., p_shadow_as_outline=false, shadow_ofs=..., p_click_pos=..., r_click_item=0x0, r_click_char=0x0, r_outside=0x0, p_char_count=0) at scene/gui/rich_text_label.cpp:170
#1  0x000000000320a8c4 in RichTextLabel::_notification (this=0xe6a7810, p_what=30) at scene/gui/rich_text_label.cpp:1025
#2  0x0000000003230d1d in RichTextLabel::_notificationv (this=0xe6a7810, p_notification=30, p_reversed=false) at scene/gui/rich_text_label.h:39
#3  0x000000000512b898 in Object::notification (this=0xe6a7810, p_notification=30, p_reversed=false) at core/object.cpp:932
#4  0x00000000037e4a5e in CanvasItem::_update_callback (this=0xe6a7810) at scene/2d/canvas_item.cpp:459
#5  0x000000000058820a in MethodBind0::call (this=0xb370ed0, p_object=0xe6a7810, p_args=0x0, p_arg_count=0, r_error=...) at ./core/method_bind.gen.inc:59
#6  0x000000000512b62f in Object::call (this=0xe6a7810, p_method=..., p_args=0x0, p_argcount=0, r_error=...) at core/object.cpp:922
#7  0x0000000005114680 in MessageQueue::_call_function (this=0x9edfb40, p_target=0xe6a7810, p_func=..., p_args=0x7ffff692b5f0, p_argcount=0, p_show_error=false) at core/message_queue.cpp:250
#8  0x0000000005114aa7 in MessageQueue::flush (this=0x9edfb40) at core/message_queue.cpp:297
#9  0x0000000002f0f555 in SceneTree::iteration (this=0xb840020, p_time=0.0166666675) at scene/main/scene_tree.cpp:483
#10 0x00000000004ae8e8 in Main::iteration () at main/main.cpp:2084
#11 0x0000000000453b75 in OS_X11::run (this=0x7fffffffd7f0) at platform/x11/os_x11.cpp:3233
#12 0x00000000004387c7 in main (argc=2, argv=0x7fffffffe008) at platform/x11/godot_x11.cpp:56

@Eoin-ONeill-Yokai
Copy link
Contributor

@Rubonnek Well, since there's currently a planned refactor (as seen in RichTextLabel issues tracker), I think that this would likely be addressed by that refactor.

Out of curiosity, do you happen to have a scene configuration where this is quickly reproducible?

@Rubonnek
Copy link
Member

@Eoin-ONeill-Yokai Unfortunately I wasn't able to reproduce the issue consistently. It just happened to me five times in a row in the same project, but suddenly it stopped happening. I spent a couple of hours trying to reproduce it but to no avail.

@Rubonnek
Copy link
Member

I can add that it always happened when one of my i3-wm windows was full screen, the project was running with a RichTextLabel node in it, and all three windows (i.e. the Editor, the running project, and my external text editor) were in the same workspace. My external editor connected to the LSP server covered the Editor as well as the project I was running, as I was debugging the code.

@Calinou Calinou changed the title Infinite loop in rich_text_label.cpp Infinite loop in rich_text_label.cpp (ERROR: _process_line: Index line = 0 is out of bounds) Nov 27, 2020
@RevoluPowered
Copy link
Contributor

I'm not using threads, for me if you enable verbose debugging and output a bunch into the godot console on re-importing an FBX file which is particularly big and click the scrollbar it will sometimes trigger the problem, but only if the log is super long.

maybe someone could make a print_verbose somewhere with like 100,000 lines into the console to debug the issue it might reveal the problem

@akien-mga
Copy link
Member

Related (likely duplicate, but both have useful debugging info) to #17815. See also #43705 which is about this issue happening when printing from threads.

@leetNightshade
Copy link

I was on 3.3.3-RC and just switched to 3.3.3-Stable, and am now seeing this issue.

@JoanPotatoes2021
Copy link

JoanPotatoes2021 commented Nov 1, 2021

I was on v3.3.3.stable.official [b973f99], running with -verbose on the editor and testing the game. I was messing with a script, and decided to run a test scene, after I pressed run scene, I noticed that the debug print panel it was still loading some texture resources from my project, the game started on the scene running, everything okay, then suddenly it frooze, upon going to the print there was the error:

ERROR: _process_line: Index line = 0 is out of bounds (l.offset_caches.size() = 0).
   At: scene/gui/rich_text_label.cpp:170

Looped to infinity until I closed Godot. I had this bug twice in a row, I was going to update to a newer version to test if it still happenned, but it suddenly stopped giving the error. I don't know what triggered, and the thing is, I never had that bug, and I did not executed any major changes aside from running with -verbose, and I also didn't edited anything related to richtextlabels in a loong while, so I cannot pinpoint the error. Also found 2 closed issues with the same problem.

#29491
#16072

@DataPlusProgram
Copy link

I've ran into this using 3.4 stable. Where the editor will indefinitely freeze up while continuously outputting:
Index line = 0 is out of bounds (l.offset_caches.size() = 0).

It happens with my plugin when threading and printing is involved.

Removing the print statements stopped the editor from outputting this error and freezing.

@resinten
Copy link

resinten commented Dec 9, 2021

I'm currently on 3.4-stable. I've had the editor periodically crash when I switch back to it after making changes in VSCode. It freezes for about 30 seconds then finally crashes. It's rare, so I don't have any idea how to reproduce it. It's been happening for several weeks. It wasn't until today that I ran the editor from the command line and saw this error message. I couldn't see whether there was anything before it in the logs because it prints it out a LOT. Weirdly, I'm not using RichTextLabel anywhere in the code, so I take it this is related to an editor UI widget thing rather than something in the scene. Also, most recently, this happened when I made changes to scripts that are not used at all in the scene that I have open, so not sure what would've caused it.

image

@Shfty
Copy link

Shfty commented Mar 1, 2022

I'm seeing this on 3.3.4 stable with scripts that run in tool mode - if I spawn a thread to parse an OBJ file and call print() from the parsing code, the editor will lock up and proceed to fill my system's RAM with error spam until killed. Evidently the offending RichTextLabel is the debug console itself in this case.

Removing the print statements prevents the issue, but also makes debugging that code next to impossible without creating a non-threaded sandbox in which to test it.

@Eoin-ONeill-Yokai
Copy link
Contributor

I'm seeing this on 3.3.4 stable with scripts that run in tool mode - if I spawn a thread to parse an OBJ file and call print() from the parsing code, the editor will lock up and proceed to fill my system's RAM with error spam until killed. Evidently the offending RichTextLabel is the debug console itself in this case.

Removing the print statements prevents the issue, but also makes debugging that code next to impossible without creating a non-threaded sandbox in which to test it.

If this is reproducible with a stack trace, could you supply a minimum testing environment? It might help with debugging.

@petterthowsen
Copy link

petterthowsen commented Mar 2, 2022

Not sure if it's related but this issue consistently happens since I tried adding multi-threading to my addon. I'll see if I can produce a minimal reproduction project but the code is so convoluted I'm having a hard time tracking down this issue.

Same here. Doing a terrain sculpting addon. I thought it went away, but it's back now :'(

I've ran into this using 3.4 stable. Where the editor will indefinitely freeze up while continuously outputting: Index line = 0 is out of bounds (l.offset_caches.size() = 0).

It happens with my plugin when threading and printing is involved.

Removing the print statements stopped the editor from outputting this error and freezing.

Seems to be the same here!

@tomeyro
Copy link

tomeyro commented Mar 12, 2022

Same happening to me. Using v3.4.3 to build an addon with multi-threads and this was popping up a lot.

I did something horrible just to be able to use print to debug:

func fakeprint(msg):
    print(msg)

Then inside a method that runs on a different thread I do:

func whatever():
    call_deferred("fakeprint", ["print me"])

@KoBeWi KoBeWi removed this from the 4.0 milestone Apr 10, 2022
@DataPlusProgram
Copy link

I am still getting this in 3.5.rc and might be able to provide additional information.

This error will not occur if the output console is minimized so that it's no longer visible.

I have also been able to get the following stack log that leads to Index line = 0 is out of bounds (l.offset_caches.size() = 0). being printed

godot.windows.opt.tools.64.exe!write_text_ansi_nolock(const int fh, const char * const buffer, const unsigned int buffer_size) Line 415	C++
godot.windows.opt.tools.64.exe!_write_nolock(int fh, const void * buffer, unsigned int buffer_size) Line 679	C++
godot.windows.opt.tools.64.exe!_write(int fh, const void * buffer, unsigned int size) Line 64	C++
godot.windows.opt.tools.64.exe!write_buffer_nolock<char>(const char c, const __crt_stdio_stream stream) Line 95	C++
[Inline Frame] godot.windows.opt.tools.64.exe!common_flush_and_write_nolock(const int) Line 174	C++
godot.windows.opt.tools.64.exe!__acrt_stdio_flush_and_write_narrow_nolock(int c, _iobuf * stream) Line 190	C++
godot.windows.opt.tools.64.exe!_fputwc_nolock(wchar_t c, _iobuf * public_stream) Line 64	C++
[Inline Frame] godot.windows.opt.tools.64.exe!__crt_char_traits<wchar_t>::puttc_nolock(const wchar_t &) Line 124	C++
[Inline Frame] godot.windows.opt.tools.64.exe!__crt_stdio_output::stream_output_adapter<wchar_t>::write_character_without_count_update(const wchar_t c) Line 166	C++
godot.windows.opt.tools.64.exe!__crt_stdio_output::output_adapter_common<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>>::write_string_impl(const wchar_t * const string, const int length, int * const count_written, __crt_deferred_errno_cache & status) Line 86	C++
[Inline Frame] godot.windows.opt.tools.64.exe!__crt_stdio_output::stream_output_adapter<wchar_t>::write_string(const wchar_t * const string, const int length, int * const count_written, __crt_deferred_errno_cache &) Line 182	C++
godot.windows.opt.tools.64.exe!__crt_stdio_output::output_processor<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>,__crt_stdio_output::standard_base<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>>>::write_stored_string_tchar(wchar_t __formal) Line 2735	C++
godot.windows.opt.tools.64.exe!__crt_stdio_output::output_processor<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>,__crt_stdio_output::standard_base<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>>>::state_case_type() Line 2150	C++
godot.windows.opt.tools.64.exe!__crt_stdio_output::output_processor<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>,__crt_stdio_output::standard_base<wchar_t,__crt_stdio_output::stream_output_adapter<wchar_t>>>::process() Line 1699	C++
godot.windows.opt.tools.64.exe!common_vfprintf::__l2::<lambda>() Line 49	C++
godot.windows.opt.tools.64.exe!__crt_seh_guarded_call<int>::operator()<<lambda_676bd5779251ec186b530f0a904b4b35>,int <lambda>(void) &,<lambda_10027885da78ada7fb00668d7e2e96b5>>(__acrt_lock_stream_and_call::__l2::<lambda_676bd5779251ec186b530f0a904b4b35> && setup, common_vfprintf::__l2::int <lambda>(void) & action, __acrt_lock_stream_and_call::__l2::<lambda_10027885da78ada7fb00668d7e2e96b5> && cleanup) Line 204	C++
[Inline Frame] godot.windows.opt.tools.64.exe!__acrt_lock_stream_and_call(_iobuf * const) Line 252	C++
[Inline Frame] godot.windows.opt.tools.64.exe!common_vfprintf(const unsigned __int64 options, _iobuf * const stream, const wchar_t * const format, __crt_locale_pointers * const locale, char * const arglist) Line 37	C++
godot.windows.opt.tools.64.exe!__stdio_common_vfwprintf(unsigned __int64 options, _iobuf * stream, const wchar_t * format, __crt_locale_pointers * locale, char * arglist) Line 73	C++
[External Code]	
godot.windows.opt.tools.64.exe!WindowsTerminalLogger::logv(const char * p_format, char * p_list, bool p_err) Line 63	C++
godot.windows.opt.tools.64.exe!Logger::logf_error(const char * p_format, ...) Line 122	C++
godot.windows.opt.tools.64.exe!WindowsTerminalLogger::log_error(const char * p_function, const char * p_file, int p_line, const char * p_code, const char * p_rationale, Logger::ErrorType p_type) Line 133	C++
godot.windows.opt.tools.64.exe!CompositeLogger::log_error(const char * p_function, const char * p_file, int p_line, const char * p_code, const char * p_rationale, Logger::ErrorType p_type) Line 284	C++
godot.windows.opt.tools.64.exe!_err_print_error(const char * p_function, const char * p_file, int p_line, const char * p_error, const char * p_message, ErrorHandlerType p_type) Line 79	C++
godot.windows.opt.tools.64.exe!_err_print_index_error(const char * p_function, const char * p_file, int p_line, __int64 p_index, __int64 p_size, const char * p_index_str, const char * p_size_str, const char * p_message, bool fatal) Line 110	C++
godot.windows.opt.tools.64.exe!RichTextLabel::_process_line(RichTextLabel::ItemFrame * p_frame, const Vector2 & p_ofs, int & y, int p_width, int p_line, RichTextLabel::ProcessMode p_mode, const Ref<Font> & p_base_font, const Color & p_base_color, const Color & p_font_color_shadow, bool p_shadow_as_outline, const Vector2 & shadow_ofs, const Vector2i & p_click_pos, RichTextLabel::Item * * r_click_item, int * r_click_char, bool * r_outside, int p_char_count) Line 930	C++
godot.windows.opt.tools.64.exe!RichTextLabel::_notification(int p_what) Line 1072	C++
godot.windows.opt.tools.64.exe!RichTextLabel::_notificationv(int p_notification, bool p_reversed) Line 38	C++
godot.windows.opt.tools.64.exe!Object::notification(int p_notification, bool p_reversed) Line 929	C++
godot.windows.opt.tools.64.exe!CanvasItem::_update_callback() Line 456	C++
godot.windows.opt.tools.64.exe!MethodBind0<CanvasItem>::call(Object * p_object, const Variant * * p_args, int p_arg_count, Variant::CallError & r_error) Line 148	C++
godot.windows.opt.tools.64.exe!Object::call(const StringName & p_method, const Variant * * p_args, int p_argcount, Variant::CallError & r_error) Line 918	C++
godot.windows.opt.tools.64.exe!MessageQueue::_call_function(Object * p_target, const StringName & p_func, const Variant * p_args, int p_argcount, bool p_show_error) Line 241	C++
godot.windows.opt.tools.64.exe!MessageQueue::flush() Line 301	C++
godot.windows.opt.tools.64.exe!SceneTree::idle(float p_time) Line 605	C++
godot.windows.opt.tools.64.exe!Main::iteration() Line 2298	C++
godot.windows.opt.tools.64.exe!OS_Windows::run() Line 3506	C++
godot.windows.opt.tools.64.exe!widechar_main(int argc, wchar_t * * argv) Line 176	C++
godot.windows.opt.tools.64.exe!_main() Line 200	C++
godot.windows.opt.tools.64.exe!main(int _argc, char * * _argv) Line 210	C++

In regards to the RichTextLabel::_process_line function it will throw the error from the following line:

if (p_mode != PROCESS_CACHE) {
		ERR_FAIL_INDEX_V(line, l.offset_caches.size(), 0);
		line_ofs = l.offset_caches[line];
	}

@DataPlusProgram
Copy link

I have created a minimal reproduction project for this issue.

In order to see the issue enable the plugin and make sure that the Godot editor output console is visible. After a few seconds it will start producing the error.

Note that if the editors output is not visible the error won't occur but the editor will soon freeze once it's visible.

The error is produced by calling this function within a thread created by the plugin:

func printOut():
	while(true):
		print("print out ------------------------------------")
		OS.delay_msec(1)

Note that decreasing the delay will cause the output text to become increasingly more garbled

richTextError.zip

@Calinou Calinou added this to the 3.x milestone Jul 15, 2022
@balloonpopper
Copy link

balloonpopper commented Aug 24, 2022

I've hit what looks to be this problem in 3.5 on Windows. After having my program lock up pretty consistently (it fails when I hit an "export" button in my project ~90% of the time) and not being able to see the error, I went back to 3.4.4 and saw the symptoms described above in the debug console.
The same as someone else mentioned above, my project is running in tool mode, and the failing code runs in a thread. The Godot process fills the ram until I kill it, and I've got the garbled text followed by infinitely looping "out of bounds" error messages.

@Eoin-ONeill-Yokai
Copy link
Contributor

Eoin-ONeill-Yokai commented Aug 24, 2022

I wonder if using call_deferred instead of call in the MessageQueue would help here. I can't help but wonder if there's some kind of String-based data race happening here where the memory gets garbled before it reaches the rich text. It might be worth a test in the next few days.

@vvwx
Copy link

vvwx commented Sep 9, 2022

I am running into the same issue.

My minimal reproduction project does not contain any scenes, scripts, exporting, or anything with threads. It is three nearly empty resource files and a project.godot

Godot version

Tested on both Mac and Linux

Reproduced with

  • 3.4.4-stable
  • 3.5-stable
  • 3.5-stable custom build (tag: 3.5-stable)
    Mac: scons platform=osx arch=arm64 target=release_debug
    Linux: scons platform=x11 arch=x64 target=release_debug
  • 3.5.1-rc1

Unable to reproduce with

  • 3.5-stable custom build (tag: 3.5-stable)
    Mac: scons platform=osx arch=arm64 target=debug
    Linux: scons platform=x11 arch=x64 target=debug
  • 4.0rc14

System information
Mac M1
Ubuntu 20.04.1

Steps to reproduce

  1. Extract the zip file somewhere, and cd into it

  2. Clear the cache and launch the editor from the command line

    • Mac

        rm -rf ~/Library/Caches/Godot
        /path/to/Godot -v --path . --editor
      
    • Linux

        rm -rf ~/.cache/godot
        /path/to/Godot_v3.5-stable_x11.64 -v --path . --editor
      
  3. In the editor, click on Output to view the output. You should see something similar to this.

     Godot Engine v3.5.stable.official (c) 2007-2022 Juan Linietsky, Ariel Manzur & Godot Contributors.
     Loaded builtin certs
     --- GDScript language server started ---
     EditorSettings: Save OK!
     Loading resource: res://dynamicfont.tres
     Loading resource: res://dynamicfontdata1.tres 
     Loading resource: res://dynamicfontdata2.tres
     Loading resource: res://dynamicfontdata1.tres
     Loading resource: res://dynamicfontdata2.tres
    
    • The Output window must remain open to reproduce the bug, so leave it open.
  4. Right click on dynamicfont.tres, then choose "Duplicate" and give it a different name.

    • You may have to do this several times (usually less than ten times, if it'll repro).
      On Mac I've had the best success; where duplicating dynamicfont.tres just once reproduces the problem.
      On Linux I've had less luck, where I'd have to duplicate dynamicfont.tres (or any of the duplicates) 5 to 10 times
      (and even quit the editor, clear the cache, and restart the editor) before the bug occurs.
  5. Watch the editor freeze.

  6. This error message is spammed in the terminal

     ERROR: Index line = 0 is out of bounds (l.offset_caches.size() = 0).
        at: _process_line (scene/gui/rich_text_label.cpp:168)
    

Video (from Mac, but similar is seen on Linux)
https://user-images.githubusercontent.com/109488824/189353599-4b3b4373-d20c-471e-9cc7-1c54aeadcdbe.mp4

Minimal reproduction project
DynamicFontInfiniteLoop.zip

Notes

  • As mentioned earlier, the Output window must be opened to reproduce the bug.
    I suspect that Output is implemented with a rich_text_label.

  • When you duplicate a resource, and the bug does not occur, you must see something like this in the Output

      Duplicating res://dynamicfont.tres -> res://a.tres
      FileSystem: calling rescan.
      Loading resource: res://a.tres
      Loading resource: res://dynamicfontdata1.tres
      Loading resource: res://dynamicfontdata2.tres
    

    If you only see

      Duplicating res://dynamicfont.tres -> res://a.tres
      FileSystem: calling rescan.
    

    Then the bug has no chance of happening. To see the bug, Godot must "reload" the resource when you duplicate it.
    To make this happen, exit the editor, clear the cache, and restart the editor
    Alternatively, name the duplicate resource something unique (in my case, b.tres hasn't been used in any editor session yet)

  • The reproduction steps clear the Godot cache. This is to ensure duplicated resources are "reloaded", even if Godot has loaded that file in a previous editor session. For example, if a previous editing session loaded a.tres, then Godot will not reload it unless if the cache was cleared before launching the editor.

  • -v (--verbose) makes it reproducible 100% of the time.
    In this minimal project, I wasn't successful in reproducing the failure without -v.
    In my actual project, the failure seemed random when -v was omitted since it only happened when Godot would also load the duplicate resource. It is obvious when Godot loads the duplicate resource because I had code that printed text when _init() was called.

  • The DynamicFont resource (dynamicfont.tres) must load two or more ExtResources. I couldn't reproduce the problem with SubResources nor with only one ExtResource.

  • This minimal project points to two ttf fonts that do not exist. The problem occurs regardless if they point to real ttfs or not.

@Eoin-ONeill-Yokai
Copy link
Contributor

I'm unable to reproduce this on master when building for x64, but it's pretty consistently cropping up when building and running the x32 version on Windows.

@akien-mga
Copy link
Member

I'm unable to reproduce this on master when building for x64, but it's pretty consistently cropping up when building and running the x32 version on Windows.

Just to be clear, do you mean that it's reproducible for a Win32 x86_32 build of the master branch? So far the results were only about 3.x and RichTextLabel has been significantly refactored in master, so I guess we assumed it fixed in 4.0. CC @bruvzg @Paulb23

@Eoin-ONeill-Yokai
Copy link
Contributor

I'm unable to reproduce this on master when building for x64, but it's pretty consistently cropping up when building and running the x32 version on Windows.

Just to be clear, do you mean that it's reproducible for a Win32 x86_32 build of the master branch? So far the results were only about 3.x and RichTextLabel has been significantly refactored in master, so I guess we assumed it fixed in 4.0. CC @bruvzg @Paulb23

@akien-mga I'll give it more testing later, but I seemed to be getting a pretty consistent crash on x86_32 build on my 64bit Windows when using master when trying one of the user's provided test project -- though the importance of this is debatable. I'll provide the backtrace when I give it more testing.

I'm not entirely sure this is a RichTextLabel / Godot problem or perhaps just a problem with the users test file as a whole (doing something weird, causing a data race which results in undefined behavior) though so I'll also look through the test project more.

@Eoin-ONeill-Yokai
Copy link
Contributor

@akien-mga Ah, the error on master is actually caused by improper cleanliness of threads in DataPlusProgram's example project. In their example, the thread should probably be stored as a member of the plugin so that it doesn't go out of scope and get (eventually) cleaned up.

So it's worth noting that particular example project might not be an accurate test.

@DataPlusProgram
Copy link

could you clarify what would be the correct way to handle this as I have moved the scope of the thread but I still see the same issues:

tool
extends EditorPlugin
var thread = Thread.new()


func printOut():
	while(true):
		print("print out ------------------------------------")
		OS.delay_msec(1)
	
	
func _ready():
	thread.start(self, "printOut")

@Eoin-ONeill-Yokai
Copy link
Contributor

Eoin-ONeill-Yokai commented Dec 22, 2022

could you clarify what would be the correct way to handle this as I have moved the scope of the thread but I still see the same issues:

Is this on 4.0 (master branch / alpha) or is this a 3.x specific issue?

I think the confusion right now is around which versions have had this issue. Judging by the gdscript example, this still looks like a 3.X related issue. I'll double back and check 3.X to see if I can find a solution that doesn't involve bundling all the changes made in 4.X. As far as I could tell, this issue is now gone in 4.X.

And yeah that should be correct now.

@DataPlusProgram
Copy link

Yes it's 3.x and still produces the same errors as a mentioned previously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests