From b3dd815817ebf3e3bb6e95b8e8b9cc6ed2c64ff8 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Thu, 28 Apr 2022 16:21:09 +0000 Subject: The syntax of the roff(7) .mc request is quite special and the roff_onearg() parsing function is too generic, so provide a dedicated parsing function instead. This fixes an assertion failure when an \o escape sequence is passed as the argument; the bug was found by tb@ using afl(1). It also makes mandoc output more similar to groff in various cases. --- mandoc.1 | 20 ++++++++++++++-- mandoc.h | 4 +++- mandoc_msg.c | 2 ++ regress/roff/Makefile | 4 ++-- regress/roff/mc/Makefile | 6 +++++ regress/roff/mc/args.in | 29 +++++++++++++++++++++++ regress/roff/mc/args.out_ascii | 19 +++++++++++++++ regress/roff/mc/args.out_lint | 9 +++++++ roff.c | 53 ++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 regress/roff/mc/Makefile create mode 100644 regress/roff/mc/args.in create mode 100644 regress/roff/mc/args.out_ascii create mode 100644 regress/roff/mc/args.out_lint diff --git a/mandoc.1 b/mandoc.1 index 415769b3..d689fffa 100644 --- a/mandoc.1 +++ b/mandoc.1 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.1,v 1.257 2022/04/24 13:38:46 schwarze Exp $ +.\" $Id: mandoc.1,v 1.258 2022/04/28 16:21:09 schwarze Exp $ .\" .\" Copyright (c) 2012, 2014-2022 Ingo Schwarze .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 24 2022 $ +.Dd $Mdocdate: April 28 2022 $ .Dt MANDOC 1 .Os .Sh NAME @@ -1754,6 +1754,15 @@ request or a layout modifier has an unknown .Ar font argument. +.It Sy "ignoring distance argument" +.Pq roff +In addition to the margin character, an +.Ic \&mc +request has a second argument supposed to represent a distance, but the +.Nm +implementation of +.Ic \&mc +always ignores the second argument. .It Sy "odd number of characters in request" .Pq roff A @@ -2124,6 +2133,13 @@ The first argument of a request is neither a single ASCII character nor a single character escape sequence. The request is ignored including all its arguments. +.It Sy "skipping unusable escape sequence" +.Pq roff +The first argument of an +.Ic mc +request is neither a single ASCII character +nor a single character escape sequence. +All arguments are ignored and printing of a margin character is disabled. .It Sy "missing manual name, using \(dq\(dq" .Pq mdoc The first call to diff --git a/mandoc.h b/mandoc.h index 32914deb..1ed0d816 100644 --- a/mandoc.h +++ b/mandoc.h @@ -1,4 +1,4 @@ -/* $Id: mandoc.h,v 1.275 2022/04/24 13:38:46 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.276 2022/04/28 16:21:09 schwarze Exp $ */ /* * Copyright (c) 2012-2022 Ingo Schwarze * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons @@ -165,6 +165,7 @@ enum mandocerr { MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */ MANDOCERR_CHAR_FONT, /* argument contains two font escapes */ MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */ + MANDOCERR_MC_DIST, /* ignoring distance argument: mc ... arg */ MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */ /* related to plain text */ @@ -221,6 +222,7 @@ enum mandocerr { MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */ MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */ MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */ + MANDOCERR_MC_ESC, /* skipping unusable escape sequence: mc arg */ MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */ MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */ MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */ diff --git a/mandoc_msg.c b/mandoc_msg.c index 0361fc80..80a49d1d 100644 --- a/mandoc_msg.c +++ b/mandoc_msg.c @@ -166,6 +166,7 @@ static const char *const type_message[MANDOCERR_MAX] = { "invalid Boolean argument", "argument contains two font escapes", "unknown font, skipping request", + "ignoring distance argument", "odd number of characters in request", /* related to plain text */ @@ -222,6 +223,7 @@ static const char *const type_message[MANDOCERR_MAX] = { "missing list type, using -item", "argument is not numeric, using 1", "argument is not a character", + "skipping unusable escape sequence", "missing manual name, using \"\"", "uname(3) system call failed, using UNKNOWN", "unknown standard specifier", diff --git a/regress/roff/Makefile b/regress/roff/Makefile index 9c9580f1..aecb314c 100644 --- a/regress/roff/Makefile +++ b/regress/roff/Makefile @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.28 2019/01/04 01:06:44 schwarze Exp $ +# $OpenBSD: Makefile,v 1.29 2022/04/28 16:16:46 schwarze Exp $ SUBDIR = args cond esc scale string -SUBDIR += br cc ce char de ds ft ig it ll na nr po ps +SUBDIR += br cc ce char de ds ft ig it ll mc na nr po ps SUBDIR += return rm rn shift sp ta ti tr while .include "../Makefile.sub" diff --git a/regress/roff/mc/Makefile b/regress/roff/mc/Makefile new file mode 100644 index 00000000..445af7d3 --- /dev/null +++ b/regress/roff/mc/Makefile @@ -0,0 +1,6 @@ +# $OpenBSD: Makefile,v 1.1 2022/04/28 16:16:46 schwarze Exp $ + +REGRESS_TARGETS = args +LINT_TARGETS = args + +.include diff --git a/regress/roff/mc/args.in b/regress/roff/mc/args.in new file mode 100644 index 00000000..4e9b245f --- /dev/null +++ b/regress/roff/mc/args.in @@ -0,0 +1,29 @@ +.\" $OpenBSD: args.in,v 1.1 2022/04/28 16:16:46 schwarze Exp $ +.TH MC-ARGS 1 "April 28, 2022" +.SH NAME +mc-args \- arguments to the .mc request +.SH DESCRIPTION +.ll 50n +.nf +initial text +.mc |suffix +ASCII character in the margin +.mc \CXX +invalid escape sequence +.mc \! +unsupported escape sequence +.mc \a +ignored escape sequence +.mc \(ba +special character in the margin +.mc \[integral] +special character represented as string +.mc \fR +font escape in the margin +.mc \N'124' +numbered character in the margin +.mc \[u007C]suffix +Unicode character in the margin +.mc \o'o/' +overstriking in the margin +.ll diff --git a/regress/roff/mc/args.out_ascii b/regress/roff/mc/args.out_ascii new file mode 100644 index 00000000..d1a56be6 --- /dev/null +++ b/regress/roff/mc/args.out_ascii @@ -0,0 +1,19 @@ +MC-ARGS(1) General Commands Manual MC-ARGS(1) + +NNAAMMEE + mc-args - arguments to the .mc request + +DDEESSCCRRIIPPTTIIOONN + initial text + ASCII character in the margin | + invalid escape sequence + unsupported escape sequence + ignored escape sequence + special character in the margin | + special character represented as string + font escape in the margin + numbered character in the margin | + Unicode character in the margin | + overstriking in the margin + +OpenBSD April 28, 2022 MC-ARGS(1) diff --git a/regress/roff/mc/args.out_lint b/regress/roff/mc/args.out_lint new file mode 100644 index 00000000..56ed4e28 --- /dev/null +++ b/regress/roff/mc/args.out_lint @@ -0,0 +1,9 @@ +mandoc: args.in:9:6: WARNING: ignoring distance argument: mc ... suffix +mandoc: args.in:11:5: WARNING: invalid escape sequence: \C +mandoc: args.in:11:5: ERROR: skipping unusable escape sequence: mc \C +mandoc: args.in:13:5: UNSUPP: unsupported escape sequence: \! +mandoc: args.in:13:5: ERROR: skipping unusable escape sequence: mc \! +mandoc: args.in:15:5: ERROR: skipping unusable escape sequence: mc \a +mandoc: args.in:21:5: ERROR: skipping unusable escape sequence: mc \fR +mandoc: args.in:25:13: WARNING: ignoring distance argument: mc ... suffix +mandoc: args.in:27:5: ERROR: skipping unusable escape sequence: mc \o'o/' diff --git a/roff.c b/roff.c index 328855c0..7bed9429 100644 --- a/roff.c +++ b/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.383 2022/04/24 17:40:22 schwarze Exp $ */ +/* $Id: roff.c,v 1.384 2022/04/28 16:21:10 schwarze Exp $ */ /* * Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons @@ -227,6 +227,7 @@ static int roff_line_ignore(ROFF_ARGS); static void roff_man_alloc1(struct roff_man *); static void roff_man_free1(struct roff_man *); static int roff_manyarg(ROFF_ARGS); +static int roff_mc(ROFF_ARGS); static int roff_noarg(ROFF_ARGS); static int roff_nop(ROFF_ARGS); static int roff_nr(ROFF_ARGS); @@ -379,7 +380,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_noarg, NULL, NULL, 0 }, /* fi */ { roff_onearg, NULL, NULL, 0 }, /* ft */ { roff_onearg, NULL, NULL, 0 }, /* ll */ - { roff_onearg, NULL, NULL, 0 }, /* mc */ + { roff_mc, NULL, NULL, 0 }, /* mc */ { roff_noarg, NULL, NULL, 0 }, /* nf */ { roff_onearg, NULL, NULL, 0 }, /* po */ { roff_onearg, NULL, NULL, 0 }, /* rj */ @@ -3731,6 +3732,54 @@ roff_eo(ROFF_ARGS) return ROFF_IGN; } +static int +roff_mc(ROFF_ARGS) +{ + struct roff_node *n; + char *cp; + + /* Parse the first argument. */ + + cp = buf->buf + pos; + if (*cp != '\0') + cp++; + if (buf->buf[pos] == '\\') { + switch (mandoc_escape((const char **)&cp, NULL, NULL)) { + case ESCAPE_SPECIAL: + case ESCAPE_UNICODE: + case ESCAPE_NUMBERED: + break; + default: + *cp = '\0'; + mandoc_msg(MANDOCERR_MC_ESC, ln, pos, + "mc %s", buf->buf + pos); + buf->buf[pos] = '\0'; + break; + } + } + + /* Ignore additional arguments. */ + + while (*cp == ' ') + *cp++ = '\0'; + if (*cp != '\0') { + mandoc_msg(MANDOCERR_MC_DIST, ln, (int)(cp - buf->buf), + "mc ... %s", cp); + *cp = '\0'; + } + + /* Create the .mc node. */ + + roff_elem_alloc(r->man, ln, ppos, tok); + n = r->man->last; + if (buf->buf[pos] != '\0') + roff_word_alloc(r->man, ln, pos, buf->buf + pos); + n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->last = n; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + static int roff_nop(ROFF_ARGS) { -- cgit v1.2.3-56-ge451