bug#81567: 31.0.90; overlay freeze

Romain Ouabdelkader <[email protected]> Fri, 7 Aug 2026 12:51:45 +0200
Newsgroups gmane.emacs.bugs
Message-ID <CAJ8YToZo-cng+bibnuE8mmei4X_3pq135aUMWgjs5cd-JCPwnA@mail.gmail.com>
Hello Eli,

> Quite crazy, IMNSHO.
I forgot to include that in my first email, disclaimer: I used LLM to
quickly generate test cases to find a simple reproducer of the issue.

I tried the patch, and I confirm that it fixed the issue.
I don't see any regression right now, I will use it for a few days to see
if I notice anything.

Thank you!

On Thu, 6 Aug 2026 at 18:29, Eli Zaretskii <[email protected]> wrote:

> > From: Romain Ouabdelkader <[email protected]>
> > Date: Thu, 6 Aug 2026 17:51:24 +0200
> >
> > The minimal reproducer I could get:
> > - two line overlays with empty 'display
> > - an overlay with 'before-string & 'display with multiple lines
>
> Quite crazy, IMNSHO.
>
> > When you scroll up to the beginning of the buffer, Emacs hangs. C-g does
> > nothing, neither does kill -SIGUSR2.
> >
> > Attached is a minimal reproducer:
> >
> > 1. emacs -Q -l overlay-scroll-freeze.el -f overlay-scroll-freeze
> > 2. hold C-p to move point to the start of the buffer
> > 3. Emacs hangs when reaching the beginning of the buffer
>
> Thanks.
>
> (Actually, you must make sure you type C-p twice in quick succession
> at BOB, otherwise there's no hang.)
>
> Please try the patch below and see if it solves the problem without
> introducing regressions elsewhere.
>
> > I am pretty sure that the issue started on emacs31; although I didn't
> > reinstall emacs30 to verify the reproducer.
>
> Emacs 30.2 indeed doesn't hang, but it produces garbled display in
> this case.
>
> diff --git a/src/xdisp.c b/src/xdisp.c
> index 5377d5e..b3227ce 100644
> --- a/src/xdisp.c
> +++ b/src/xdisp.c
> @@ -11298,10 +11298,18 @@ move_it_vertically_backward (struct it *it, int
> dy)
>       y-distance.  */
>    SAVE_IT (it2, *it, it2data);
>    it2.max_ascent = it2.max_descent = 0;
> +  ptrdiff_t to_pos = start_pos;
>    do
>      {
> +      /* Avoid inflooping of there's a large display string with several
> +         embedded newlines, which makes move_it_to stop after START_POS
> +         but still inside a display or overlay string.  */
> +      if (IT_CHARPOS (it2) >= start_pos)
> +       to_pos = -1;
>        move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
> -                 MOVE_TO_POS | MOVE_TO_VPOS);
> +                 (to_pos > 0
> +                   ? (MOVE_TO_POS | MOVE_TO_VPOS)
> +                  : MOVE_TO_VPOS));
>      }
>    while (!(IT_POS_VALID_AFTER_MOVE_P (&it2)
>            /* If we are in a display string which starts at START_POS,
>