Package: emacs;
Reported by: Yifan Zhu <fanzhuyifan <at> gmail.com>
Date: Mon, 17 Mar 2025 07:54:03 UTC
Severity: normal
Found in version 31.0.50
Done: Eli Zaretskii <eliz <at> gnu.org>
Bug is archived. No further changes may be made.
Message #41 received at 77065 <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 77065 <at> debbugs.gnu.org Subject: Re: bug#77065: 31.0.50; Infinite loop in move_it_to Date: Mon, 17 Mar 2025 19:36:15 -0700
On 3/17/25 7:27 AM, Eli Zaretskii wrote: > Thanks, but I don't have access to a system where these prerequisites > can be met. So either someone can reproduce this, debug the problem, > and describe the reason for the loop, or I'd need to ask you to do it, > if possible. Or, if you can show a recipe for reproducing the problem > without installing LaTeX and xenops, I could try reproducing this on > the systems to which I have access. Right now I have a conjecture about what might be causing the infinite loop -- when line number are produced, we can no longer use it->hpos == 0 to test if the glyph is the first glyph. Perhaps this is best explained by the following diff: diff --git a/src/xdisp.c b/src/xdisp.c index d7e0691c44d..0f4210ab814 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -9972,6 +9972,7 @@ move_it_in_display_line_to (struct it *it, ptrdiff_t prev_pos = IT_CHARPOS (*it); bool saw_smaller_pos = prev_pos < to_charpos; bool line_number_pending = false; + int initial_hpos = 0; int this_line_subject_to_line_prefix = 0; #ifdef GLYPH_DEBUG @@ -10037,7 +10038,10 @@ #define BUFFER_POS_REACHED_P() \ && should_produce_line_number (it)) { if (it->current_x == it->first_visible_x) - maybe_produce_line_number (it); + { + maybe_produce_line_number (it); + initial_hpos = it->hpos; + } else line_number_pending = true; } @@ -10298,7 +10302,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \ if (/* IT->hpos == 0 means the very first glyph doesn't fit on the line, e.g. a wide image. */ - it->hpos == 0 + it->hpos == initial_hpos || (new_x == it->last_visible_x && FRAME_WINDOW_P (it->f))) { @@ -10474,6 +10478,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \ line_number_pending = false; it->current_x = it->first_visible_x; maybe_produce_line_number (it); + initial_hpos = it->hpos; it->current_x += new_x - it->first_visible_x; } /* Glyph is visible. Increment number of glyphs that Some other evidence includes the following gdb session: (TLDR: in `move_it_in_display_line_to`, maybe_produce_line_number increases it->hpos from 0 to 4. Thus afterwards the test for the glyph being the first one fails) (gdb) r ~/Downloads/main.tex +r ~/Downloads/main.tex Starting program: /home/yifan/packages/emacs-git/build/bin/emacs ~/Downloads/main.tex ^Z Thread 1 "emacs" received signal SIGTSTP, Stopped (user). (gdb) bt #0 0x00005555556f54c5 in EQ (x=0x5555570825c4, y=0x5555570825c4) at /home/yifan/packages/emacs-git/src/lisp.h:1327 #1 0x00005555557002e8 in face_attr_equal_p (v1=0x5555570825c4, v2=0x5555570825c4) at xfaces.c:4417 #2 0x0000555555700416 in lface_equal_p (v1=0x5555588380d0, v2=0x7ffffffecc80) at xfaces.c:4450 #3 0x000055555570157d in lookup_face (f=0x555555ecda90, attr=0x7ffffffecc80) at xfaces.c:5012 #4 0x00005555557018c0 in lookup_named_face (w=0x555555ecdce8, f=0x555555ecda90, symbol=0x67e0, signal_p=false) at xfaces.c:5099 #5 0x0000555555701bd4 in lookup_basic_face (w=0x555555ecdce8, f=0x555555ecda90, face_id=0) at xfaces.c:5163 #6 0x0000555555664ed2 in produce_special_glyphs (it=0x7ffffffee420, what=IT_CONTINUATION) at xdisp.c:32433 #7 0x000055555560d7e8 in init_iterator (it=0x7ffffffee420, w=0x555555ecdce8, charpos=-1, bytepos=-1, row=0x5555559f8ba0 <scratch_glyph_row>, base_face_id=DEFAULT_FACE_ID) at xdisp.c:3365 #8 0x000055555564ce8d in maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25201 #9 0x000055555561f53e in move_it_in_display_line_to (it=0x7fffffff6e20, to_charpos=307, to_x=-1, op=MOVE_TO_POS) at xdisp.c:10040 #10 0x0000555555622e6c in move_it_to (it=0x7fffffff6e20, to_charpos=307, to_x=-1, to_y=-1, to_vpos=-1, op=8) at xdisp.c:10945 #11 0x0000555555623a79 in move_it_vertically_backward (it=0x7fffffff9700, dy=448) at xdisp.c:11159 #12 0x000055555563e600 in redisplay_window (window=0x555555ecdced, just_this_one_p=false) at xdisp.c:20925 #13 0x00005555556349fd in redisplay_window_0 (window=0x555555ecdced) at xdisp.c:18230 #14 0x00005555557f1e3e in internal_condition_case_1 (bfun=0x5555556349bb <redisplay_window_0>, arg=0x555555ecdced, handlers=0x7fffef32b4b3, hfun=0x555555634899 <redisplay_window_error>) at eval.c:1644 #15 0x000055555563486f in redisplay_windows (window=0x555555ecdced) at xdisp.c:18199 #16 0x000055555563481e in redisplay_windows (window=0x5555587c5bcd) at xdisp.c:18193 #17 0x0000555555633616 in redisplay_internal () at xdisp.c:17616 #18 0x00005555556315c3 in redisplay () at xdisp.c:16772 #19 0x000055555572b711 in read_char (commandflag=1, map=0x55555851b4e3, prev_event=0x0, used_mouse_menu=0x7fffffffd73a, end_time=0x0) at keyboard.c:2672 #20 0x000055555573e443 in read_key_sequence (keybuf=0x7fffffffd9b0, prompt=0x0, dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false, disable_text_conversion_p=false) at keyboard.c:10757 #21 0x0000555555727d97 in command_loop_1 () at keyboard.c:1424 #22 0x00005555557f1d97 in internal_condition_case (bfun=0x555555727989 <command_loop_1>, handlers=0x90, hfun=0x555555726eba <cmd_error>) at eval.c:1620 #23 0x00005555557275d6 in command_loop_2 (handlers=0x90) at keyboard.c:1163 #24 0x00005555557f12ec in internal_catch (tag=0x11f10, func=0x5555557275ac <command_loop_2>, arg=0x90) at eval.c:1300 #25 0x0000555555727568 in command_loop () at keyboard.c:1141 #26 0x0000555555726a5c in recursive_edit_1 () at keyboard.c:749 #27 0x0000555555726c08 in Frecursive_edit () at keyboard.c:832 #28 0x0000555555722cc5 in main (argc=2, argv=0x7fffffffde98) at emacs.c:2560 (gdb) break move_it_in_display_line_to +break move_it_in_display_line_to Breakpoint 2 at 0x55555561f329: file xdisp.c, line 9963. (gdb) c +c Continuing. Thread 1 "emacs" hit Breakpoint 2, move_it_in_display_line_to (it=0x7fffffff6e20, to_charpos=307, to_x=-1, op=MOVE_TO_POS) at xdisp.c:9963 9963 { (gdb) watch it->hpos +watch it->hpos Hardware watchpoint 3: it->hpos (gdb) p it->hpos +p it->hpos $1 = 0 (gdb) c +c Continuing. Thread 1 "emacs" hit Hardware watchpoint 3: it->hpos Old value = 0 New value = 1 maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25292 25292 if (p) (gdb) +c Continuing. Thread 1 "emacs" hit Hardware watchpoint 3: it->hpos Old value = 1 New value = 2 maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25292 25292 if (p) (gdb) +c Continuing. Thread 1 "emacs" hit Hardware watchpoint 3: it->hpos Old value = 2 New value = 3 maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25292 25292 if (p) (gdb) +c Continuing. Thread 1 "emacs" hit Hardware watchpoint 3: it->hpos Old value = 3 New value = 4 maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25292 25292 if (p) (gdb) fini +fini Run till exit from #0 maybe_produce_line_number (it=0x7fffffff6e20) at xdisp.c:25292 0x000055555561f53e in move_it_in_display_line_to (it=0x7fffffff6e20, to_charpos=307, to_x=-1, op=MOVE_TO_POS) at xdisp.c:10040 10040 maybe_produce_line_number (it); (gdb) next +next 10045 if (it->area == TEXT_AREA && !it->string_from_prefix_prop_p) (gdb) +next 10046 handle_line_prefix (it); (gdb) +next 10051 this_line_subject_to_line_prefix = it->string_from_prefix_prop_p; (gdb) +next 10054 if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) (gdb) +next 10059 int x, i, ascent = 0, descent = 0; (gdb) +next 10068 if ((op & MOVE_TO_POS) != 0 (gdb) +next 10069 && BUFFERP (it->object) (gdb) +next 10070 && it->method == GET_FROM_BUFFER (gdb) +next 10110 if (!get_next_display_element (it)) (gdb) +next 10116 if (it->line_wrap == TRUNCATE) (gdb) +next 10135 if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA) (gdb) +next 10137 bool next_may_wrap = may_wrap; (gdb) +next 10139 if (char_can_wrap_after (it)) (gdb) +next 10140 next_may_wrap = true; (gdb) +next 10144 if (may_wrap && char_can_wrap_before (it)) (gdb) +next 10170 may_wrap = next_may_wrap; (gdb) +next 10176 ascent = it->max_ascent; (gdb) +next 10177 descent = it->max_descent; (gdb) +next 10183 x = it->current_x; (gdb) +next 10185 PRODUCE_GLYPHS (it); (gdb) +next 10187 if (it->area != TEXT_AREA) (gdb) +next 10222 if (it->nglyphs) (gdb) +next 10226 int single_glyph_width = it->pixel_width / it->nglyphs; (gdb) +next 10228 int x_before_this_char = x; (gdb) +next 10229 int hpos_before_this_char = it->hpos; (gdb) +next 10231 for (i = 0; i < it->nglyphs; ++i, x = new_x) (gdb) +next 10233 new_x = x + single_glyph_width; (gdb) +next 10236 if ((op & MOVE_TO_X) && new_x > to_x) (gdb) +next 10271 it->line_wrap != TRUNCATE (gdb) +next 10270 if (/* Lines are continued. */ (gdb) +next 10273 new_x > it->last_visible_x (gdb) +next 10272 && (/* And glyph doesn't fit on the line. */ (gdb) +next 10284 && (!this_line_subject_to_line_prefix (gdb) +next 10296 bool moved_forward = false; (gdb) +next 10301 it->hpos == 0 (gdb) +next 10298 if (/* IT->hpos == 0 means the very first glyph (gdb) +next 10302 || (new_x == it->last_visible_x (gdb) +next 10414 IT_RESET_X_ASCENT_DESCENT (it); (gdb) quit
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.