On Mon, Oct 27, 2025 at 08:41:31PM +0000, Gavin Smith wrote:
> On Mon, Oct 27, 2025 at 03:10:04PM +0800, aidan wrote:
> > -
> >
> > To the GNU Info maintainers,
> >
> > Hello. I believe I have found a reproducible crash in the standalone Info
> > reader.
> > -
>
> I can confirm this. It doesn't just crash but seemed to freeze up my
> system for a few seconds, before exiting and "illed" (sic) was printed at the
> commmand line. Running this in gdb I can see that the program is terminated
> with SIGKILL.
>
> In fact, it is killed even without pressing return, if you hold tab down
> for long enough.
>
> I haven't tracked down exactly where the crash occurs yet but it is somewhere
> in info_read_in_echo_area or read_and_dispatch_in_echo_area in echo-area.c.
> I will investigate more in the next couple of days as I have time.
It crashes after 32 tab characters are typed. At 8 screen columns per
tab this is after 256 columns.
Exponentially more memory is used in line_map_add which exhausts the available
memory. This is called from window_compute_line_map in the loop:
/* Set pchars */
(void) printed_representation (&iter, &delim, win->line_map.used,
&pchars, &pbytes);
while (pchars--)
line_map_add (&win->line_map, cur_ptr - win->node->contents, pchars);
When the crash occurs, pchars has a negative value, which led to the loop
not terminating.
Inside printed_representation, I find the comment:
else if (*cur_ptr == '\t')
{
int i = 0;
/* compute the number of columns to the next tab stop, assuming
8 columns for a tab.
To determine the next tab stop, add 8 to the current column,
and then subtract the remainder of the division by 8.
(n & 0xf8) does (n - n mod 8) in one step as the binary
representation of 0xf8 is 1111 1000 so the result has
to be a multiple of 8.
TODO this doesn't work if there are more than 255 columns.
*/
*pchars = ((pl_chars + 8) & 0xf8) - pl_chars;
*pbytes = *pchars;
This comment was added after a discussion of this code:
https://lists.gnu.org/archive/html/bug-texinfo/2024-10/msg00095.html
Patrice's doubt about this code was well-founded, as it appears to
be wrong.
The code has gone through some changes but the bug is likely very old,
as similar logic was also in commit 16440098c622 (2002-08-25) which was
the initial import into version control:
case '\t':
{
int tw;
tw = ((hpos + 8) & 0xf8) - hpos;
while (i < tw)
SC(' ');
break;
}
In that commit, hpos was an "int" rather than "size_t" but it still looks
wrong as an int could have a value greater than 0xff.
It can be fixed to clear the three least significant bits correctly:
*pchars = ((pl_chars + 8) & ~0x07) - pl_chars;
With this change, the crash no longer occurs.