Re: To bust or not to bust: the C/C++ code freeze for a (poor man's) fuzzer-provoked SEGV

"G. Branden Robinson" <[email protected]>
Newsgroups gmane.comp.printing.groff.general
Message-ID <20260131012815.iqu6jvaztdwpohlv@illithid>
I'm planning to bust the C/C++ code freeze for my next push...

...but only with an ice auger and monofilament fishing line (that is, on
a tightly limited basis), to fix the assertion failure Deri observed
(and which anyone should be able to reproduce).

We only got 3 opinions on the other SEGV, which is many years old and
the "vote" was 2-to-1 (with many abstentions) against busting the freeze
for it, whereas this one is a regression from groff 1.23.0.

At 2026-01-28T18:23:46-0600, G. Branden Robinson wrote:
> At 2026-01-28T23:03:28+0000, Deri wrote:
> > I only discovered it when doing the research for the pdf attached to
> > <https:// savannah.gnu.org/bugs/?67544#comment8>. I wanted to attach
> > a .png at the top of the page:-
> > 
[snipping down to reproducer]
> > \X'pdf: pdfpic ne-pic.png -L \n[LL]z'
> > .sp 1.4c
> > .NH 1 ghostscript
> > Ghostscript
> > 
> > It only avoided the SIGSEGV if I added a .LP before it.
> 
> Insofar as you had to issue an `LP` call before populating your ms(7)
> document with content, then it's not a bug that you got an undesirable
> outcome when you omitted it.
[...]
> However, a core dump should not be GNU troff's means of informing you
> that you erred.
> 
> I'll test my excessively advanced input stream pointer hypothesis
> presently.

I didn't get the problem root-caused but I have backed off slightly from
this hypothesis, because I can cause _almost_ the same problem without
using an escape sequence, or selecting the "pdf" output driver.

$ ~/groff-HEAD/bin/groff -version | head -n 1
GNU groff version 1.24.0.rc2
$ printf '\\X"pdf: xrev"' | ~/groff-HEAD/bin/groff -ms
troff: src/roff/troff/input.cpp:3107: const char* token::description(): Assertion `0 == "unhandled case of `type` (token)"' failed.
/home/branden/groff-HEAD/bin/groff: error: troff: Aborted (core dumped)
$ echo '.device pdf: xrev' | ~/groff-HEAD/bin/groff -ms -a
<beginning of page>
troff:<standard input>:1: error: spurious end trap token detected!
df: xrev

Notice how there's no core dump, just an ill-formatted document.  And
the ill-formatting is an outcome of which ms(7) users have been warned
since at least 1976 (before `\X` even existed).

The output still suggests input stream pointer shenanigans to me, but
not located quite where I thought they were (in the `\X` escape sequence
handler).  Something else could be amiss.

And rather than go chasing down how to make the formatter or the macro
package recover better from ill-formed input, knowing that if I choose
(or am compelled to) the latter, fixes to me(7) and mm(7) will likely
_also_ be required because they too are designed to require macro calls
before they complete initialization, and knowing myself well enough that
if I start down this road I'm likely to see other problems I develop an
animal lust to fix, I think I'd rather just--to adapt Deri's analogy
from discussion of an unrelated issue--put a sticking plaster over this
one.

Here's the patch:

$ git diff --cached
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index 944f9bcd9..1fe5b1631 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -3103,6 +3103,19 @@ const char *token::description()
     return "an escaped ':'";
   case TOKEN_EOF:
     return "end of input";
+  // troff generates the following token types internally; the input
+  // can't (directly), so seeing them described likely suggests a bug in
+  // the formatter.  We consequently don't attempt to make their
+  // descriptions intelligible to the novice.
+  case TOKEN_BEGIN_TRAP:
+    return "a \"begin trap\" token";
+  case TOKEN_END_TRAP:
+    return "an \"end trap\" token";
+  // TOKEN_NODE is handled above
+  case TOKEN_PAGE_EJECTOR:
+    return "a \"page ejector\" token";
+  case TOKEN_REQUEST:
+    return "a \"request\" token";
   default:
     assert(0 == "unhandled case of `type` (token)");
     return "an undescribed token";

Turns out there were only four token types unhandled.  That's not even
really a sticking plaster; as the comment notes, we can leave this
diagnostic information in there forever, because these descriptions
should only ever come up when a groff developer has erred.

Result?

$ printf '\\X"pdf: xrev"' | ./build/test-groff -ms -a
<beginning of page>
troff:<standard input>:1: warning: a "begin trap" token is not encodable in device-independent output ('asciify' might help)
troff:<standard input>:1: error: spurious end trap token detected!
. pdf: xrev"

Code reviews?  Any objections?

Savannah ticket: https://savannah.gnu.org/bugs/?67990

Regards,
Branden
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEh3PWHWjjDgcrENwa0Z6cfXEmbc4FAml9WqgACgkQ0Z6cfXEm
bc5zbg//YXfUTNoa4+meAXcdUMDu6I9WMlHq32E+cRO9TkTclu2i6gTX7Gx6gZXN
WkyWPpMZZ8tHZOZ/xOGg1Ff9bRs0MfcFLj9NkUORJHOXVnz7ZUe8EaK0fmGtjddq
1j808uHnt4tzAWNo2/KVQpZoJWZqqXszEcAuhHLt8O5szbyiIXr47c1LCZINvUEL
Vf4ZP5e1WVrvdOK61jI7BiqdBDmOvTmf7Q6zupTd3aHHJr/mZrQRjPNYNNXf5scU
0X98vZTo57zSXUV96fb0OebafeZwkkiak85vADl3YYMkpJyHx2QFpHS9v9Zdu+YZ
27NWH6sPb4JJASjqPtdvbkTMaH5Zonaj2YOrLV78S177ZMUnddjKBJrdC277NEfG
Nl4DJ49vsgFOQWlGWn/mFJK/X4uHii+cSWCEF5UOBmVIe1YrOS4pbwAoRQvsW7zG
Km4Y93IHk/omoy+I9r4pDRqBx5BirD0TXDU7NKVT3feJa/SvPRecq00GHUnsR12Y
QidH9Ws/A9s5Lw18oRhOctRCjVK1Mu4GJaYB+kPvvz//2Pzef7aXhnqMGs5HFrRn
k4TpzKRI9DuWGFry4qSTjcj+Z5B8oC+vtJxwRG5t8O8GWktbLlNhhQ5PrJLxBinG
NjP/DMVKMcrrTxxINSswHG01kHDl+uY3OdiRvChy61VM7Xgtw2M=
=GMcr
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.