summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2014-12-18 03:09:43 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2014-12-18 03:09:43 +0000
commit056ee0f65d8f88f85b31dd29b7bfa69d338773ec (patch)
treeff92057d7437c57e0c539af850e36208ec31a819
parent1aae07193c320a8878e92af7cb8ee670be6de185 (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.in21
-rw-r--r--regress/usr.bin/mandoc/mdoc/Bl/break.out_ascii12
-rw-r--r--regress/usr.bin/mandoc/mdoc/Bl/break.out_lint12
-rw-r--r--usr.bin/mandoc/mdoc.h3
-rw-r--r--usr.bin/mandoc/mdoc_macro.c53
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,