mandoc(1) crashes with a core dump if it cannot parse a manual page. How to repeat: # FreeBSD 14.0-CURRENT curl -sSf https://people.freebsd.org/~wosch/tmp/mandoc/core-dumped/krb5_openlog.3 | mandoc >/dev/null Assertion failed: (*sz == 2 && (*start)[0] == '.' && (*start)[1] == 'T'), function mandoc_escape, file /usr/src/contrib/mandoc/mandoc.c, line 467. Abort trap (core dumped) # FreeBSD 13.1-STABLE curl -sSf https://people.freebsd.org/~wosch/tmp/mandoc/core-dumped/krb5_openlog.3 | mandoc >/dev/null Abort trap (core dumped)
reported upstream still valid in latest CVS version
Actually, with mandoc-current, i get a different assertion, but in the same function, and judging from what i know about the code, i hold a strong suspicion that the root cause is still the same, i.e. that the same invariant is still being violated in the code: $ mandoc krb5_openlog.3 assertion "rval != ESCAPE_EXPAND" failed: file "/usr/src/usr.bin/mandoc/roff_escape.c", line 46, function "mandoc_escape" Abort trap (core dumped) This is a very important bug report because this particular bug has already been reported a few weeks ago, but the reporter was unable to provide a reproducer. I tried to construct a reproducer from code inspection but unfortunately failed. So having the rproducer is very valuable. Right now, we are in the middle of an OpenBSD release, so it will take up to a week before i will find the time of looking into this. Apparently, the bug is that some particular roff(7) escape sequence is likely regarded as output-device-dependent by the roff(7) pre-parser and hence not substituted but instead left for the formatters to handle, similar to the \*(.T predefined string, but the formatters regards that particular escape sequence as one that should have been replaced by the pre-parser, hence dying because they cannot handle it. Having a quick look at your reproducing input file, i suspect that the following input confuses mandoc: .\" ouch! .ds xx \\*(fP\fR(\fP\\*(lI*\\*(fP Notably, you already marked that line with "ouch" in the manual page source code, presumably acknowledging that doing such low-level gymnastics in a manual page is asking for trouble. To not handle such madness gracefully is still a bug in mandoc though, i do not deny that. I suspect that using the extremely special escape sequence "\\" inside .ds is confusing mandoc - that sequence is mostly intended for being used inside .de. The pre-parser still sees the "\\" and consequently sees no user-defined string replacement escape sequences. But when the "xx" string is later used, the "\\*" likely gets resolved to "\*", i.e. to a string replacement request, but at the point, the pre-parser has already been run so the string does not get replaced and makes it through to the formatters, and those cannot handle it. Or something like that, i will have to investigate in detail. No wonder i was unable to construct a reproducer from scratch, given how crazy the reproducer actually looks...
I believe the following commit dixes the issue: https://cvsweb.bsd.lv/mandoc/roff.c#rev1.397 A longer explanation, also including the patch, is available here: https://marc.info/?l=mandoc-tech&m=169791069132614