[tex-k] Bug in web2c or MF: segfault using scantokens in recursive macro

Karl Berry karl at freefriends.org
Wed Nov 15 22:38:16 CET 2023

    I tested some other inputs and each of the following lines also
    throws a segfault:

I'm guessing it's all the same cause. DRF found (see below) that the
recursive expansion continues until mf's mem runs out, and the system
stack size is generally smaller than that.

We implemented an expand_depth constant for TeX, precisely to avoid this
problem (10000 by default), but never bothered to do the same for mf.
And I'm not much inclined to spend the time myself at this
point. Patches welcome :), though.

One might argue that Knuth should have implemented this kind of check
instead of just running out of memory, but I don't think he'd be
interested at this late date. So I'm planning to add it to nobug
.. --thanks, karl.

Date: Wed, 15 Nov 2023 19:45:33 +0000 (UTC)
From: David Fuchs

Right, trying with my unmodified MF also ends up in an infinite
recursion and crashes with a stack overflow:

stack-overflow ...
    #0 0x102ddc8c8 in get_x_next 
    #1 0x102e178d0 in expand 
    #2 0x102ddc930 in get_x_next 
    #3 0x102e25410 in scan_primary 
    #4 0x102e178d0 in expand 
    #5 0x102ddc930 in get_x_next 
    #6 0x102e25410 in scan_primary 
    #7 0x102e178d0 in expand 
.. with those last 3 continuing to repeat.

But, that's a fair question as to why MF didn't complain first, about
running out of some resource or another.  So, I re-linked MF with
an 8Mb stack (rather than the default 1Mb(?)), and voila:

! METAFONT capacity exceeded, sorry [main memory size=65535].
<*> def?=scantokens""?enddef;?
Transcript written on mfput.log.

Setting a breakpoint at jump_out, the debugger tells that we're about
90,000 stack frames deep at this point.  It seems that
stash_cur_exp (called from get_x_next) has been allocating 2 words of
mem per every 3 frames of function nesting (scan_primary, expand,
get_x_next), and 2*90k/3 matches MF's available main memory pretty well;
while on the other hand, 8Mb / 30k = 266 bytes of stack space for each 3
frames matches the assembly code generated by the C compiler (128, 80,
32 subtracted from sp, respectively, and that sums to 240) close

So, it all makes sense.  I suppose the moral to the story is that
maybe maybe maybe we should build with a bigger stack by default, or
probably just say "yeah, don't do that."  -drf

p.s. For reference/posterity: I added the magic
invocation -Wl,-stack_size,0x800000 to get the 8Mb stack space,
which is enough for "normal, non-debug" compiles of MF; it had to be
more when I turned on runtime-checking and full debugging . 

More information about the tex-k mailing list.