diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2014-12-18 03:09:43 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2014-12-18 03:09:43 +0000 |
commit | 056ee0f65d8f88f85b31dd29b7bfa69d338773ec (patch) | |
tree | ff92057d7437c57e0c539af850e36208ec31a819 | |
parent | 1aae07193c320a8878e92af7cb8ee670be6de185 (diff) |
The code is already careful to not add items to lists that were
already closed. In this respect, also consider lists closed
that have broken another block, their closure pending until the
end of the broken block. This avoids syntax tree corruption
leading to a NULL pointer access found by jsg@ with afl.
-rw-r--r-- | regress/usr.bin/mandoc/mdoc/Bl/break.in | 21 | ||||
-rw-r--r-- | regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii | 12 | ||||
-rw-r--r-- | regress/usr.bin/mandoc/mdoc/Bl/break.out_lint | 12 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.h | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_macro.c | 53 |
5 files changed, 73 insertions, 28 deletions
diff --git a/regress/usr.bin/mandoc/mdoc/Bl/break.in b/regress/usr.bin/mandoc/mdoc/Bl/break.in index a397042d27b..4fe9246b5bf 100644 --- a/regress/usr.bin/mandoc/mdoc/Bl/break.in +++ b/regress/usr.bin/mandoc/mdoc/Bl/break.in @@ -1,4 +1,4 @@ -.Dd November 16, 2012 +.Dd December 18, 2014 .Dt BL-BREAK 1 .Os OpenBSD .Sh NAME @@ -13,6 +13,15 @@ before bracket .El after list .Bc +in between +.Bl -enum -offset indent +.It +before bracket +.Bo inside both +.El +.It +stray item +.Bc after both .Sh EXAMPLES .Bl -enum -offset indent @@ -23,6 +32,16 @@ inside both .El after display .Ed +in between +.Bl -enum -offset indent +.It +before display +.Bd -ragged -offset indent +inside both +.El +.It +stray item +.Ed after both .Sh CAVEATS .Bl -hang diff --git a/regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii b/regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii index 46218053f9d..ed14c25d910 100644 --- a/regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii +++ b/regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii @@ -7,15 +7,25 @@ DDEESSCCRRIIPPTTIIOONN before both 1. before bracket [inside both after list] + in between + + 1. before bracket [inside both + stray item] after both EEXXAAMMPPLLEESS 1. before display inside both after display + in between + + 1. before display + + inside both + stray item after both CCAAVVEEAATTSS before broken block [inside both after list] -OpenBSD November 16, 2012 OpenBSD +OpenBSD December 18, 2014 OpenBSD diff --git a/regress/usr.bin/mandoc/mdoc/Bl/break.out_lint b/regress/usr.bin/mandoc/mdoc/Bl/break.out_lint index b99744f21b2..70b3c986446 100644 --- a/regress/usr.bin/mandoc/mdoc/Bl/break.out_lint +++ b/regress/usr.bin/mandoc/mdoc/Bl/break.out_lint @@ -1,5 +1,9 @@ mandoc: break.in:13:2: WARNING: blocks badly nested: El breaks Bo -mandoc: break.in:23:2: WARNING: blocks badly nested: El breaks Bd -mandoc: break.in:30:2: WARNING: blocks badly nested: El breaks It -mandoc: break.in:29:25: ERROR: appending missing end of block: Bo -mandoc: break.in:28:2: ERROR: appending missing end of block: Bl +mandoc: break.in:21:2: WARNING: blocks badly nested: El breaks Bo +mandoc: break.in:22:2: ERROR: skipping item outside list: It +mandoc: break.in:32:2: WARNING: blocks badly nested: El breaks Bd +mandoc: break.in:41:2: WARNING: blocks badly nested: El breaks Bd +mandoc: break.in:42:2: ERROR: skipping item outside list: It +mandoc: break.in:49:2: WARNING: blocks badly nested: El breaks It +mandoc: break.in:48:25: ERROR: appending missing end of block: Bo +mandoc: break.in:47:2: ERROR: appending missing end of block: Bl diff --git a/usr.bin/mandoc/mdoc.h b/usr.bin/mandoc/mdoc.h index f19a8054d4b..24c257935c9 100644 --- a/usr.bin/mandoc/mdoc.h +++ b/usr.bin/mandoc/mdoc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mdoc.h,v 1.57 2014/11/28 19:25:03 schwarze Exp $ */ +/* $OpenBSD: mdoc.h,v 1.58 2014/12/18 03:09:42 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -356,6 +356,7 @@ struct mdoc_node { enum mdoct tok; /* tok or MDOC__MAX if none */ int flags; #define MDOC_VALID (1 << 0) /* has been validated */ +#define MDOC_BREAK (1 << 1) /* has broken another block */ #define MDOC_EOS (1 << 2) /* at sentence boundary */ #define MDOC_LINE (1 << 3) /* first macro/text on line */ #define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */ diff --git a/usr.bin/mandoc/mdoc_macro.c b/usr.bin/mandoc/mdoc_macro.c index b71a1fbc4e1..3dbd6602e8c 100644 --- a/usr.bin/mandoc/mdoc_macro.c +++ b/usr.bin/mandoc/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mdoc_macro.c,v 1.113 2014/12/13 13:13:26 schwarze Exp $ */ +/* $OpenBSD: mdoc_macro.c,v 1.114 2014/12/18 03:09:42 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org> @@ -476,12 +476,16 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, for (breaker = broken->parent; breaker; breaker = breaker->parent) { /* - * If the *broken block had already been broken before - * and we encounter its breaker, make the tok block - * pending on the inner breaker. - * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]" - * becomes "[A broken=[B [C->B B] tok=A] C]" - * and finally "[A [B->A [C->B B] A] C]". + * If the *broken block (Z) is already broken and we + * encounter its breaker (B), make the tok block (A) + * pending on that inner breaker (B). + * Graphically, [A breaker=[B! broken=[Z->B B] tok=A] Z] + * becomes breaker=[A broken=[B! [Z->B B] tok=A] Z] + * and finally [A! [B!->A [Z->B B] A] Z]. + * In these graphics, "->" indicates the "pending" + * pointer and "!" indicates the MDOC_BREAK flag. + * Each of the cases gets one additional pointer (B->A) + * and one additional flag (A!). */ if (breaker == broken->pending) { broken = breaker; @@ -495,31 +499,38 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, /* * Found the breaker. - * If another, outer breaker is already pending on - * the *broken block, we must not clobber the link + * If another, outer breaker (X) is already pending on + * the *broken block (B), we must not clobber the link * to the outer breaker, but make it pending on the - * new, now inner breaker. - * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]" - * becomes "[A breaker=[B->A broken=[C A] tok=B] C]" - * and finally "[A [B->A [C->B A] B] C]". + * new, now inner breaker (A). + * Graphically, [X! breaker=[A broken=[B->X X] tok=A] B] + * becomes [X! breaker=[A->X broken=[B X] tok=A] B] + * and finally [X! [A!->X [B->A X] A] B]. */ if (broken->pending) { struct mdoc_node *taker; /* - * If the breaker had also been broken before, - * it cannot take on the outer breaker itself, - * but must hand it on to its own breakers. - * Graphically, this is the following situation: - * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]" - * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]" + * If the inner breaker (A) is already broken, + * too, it cannot take on the outer breaker (X) + * but must hand it on to its own breakers (Y): + * [X! [Y! breaker=[A->Y Y] broken=[B->X X] tok=A] B] + * [X! take=[Y!->X brea=[A->Y Y] brok=[B X] tok=A] B] + * and finally [X! [Y!->X [A!->Y Y] [B->A X] A] B]. */ taker = breaker; while (taker->pending) taker = taker->pending; taker->pending = broken->pending; } + + /* + * Now we have reduced the situation to the simplest + * case, which is just breaker=[A broken=[B tok=A] B] + * and becomes [A! [B->A A] B]. + */ broken->pending = breaker; + breaker->flags |= MDOC_BREAK; mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[broken->tok]); @@ -1065,8 +1076,8 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_It) { for (n = mdoc->last; n; n = n->parent) - if (n->tok == MDOC_Bl && - ! (n->flags & MDOC_VALID)) + if (n->tok == MDOC_Bl && n->type == MDOC_BLOCK && + ! (n->flags & (MDOC_VALID | MDOC_BREAK))) break; if (n == NULL) { mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, |