diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2017-02-16 09:47:31 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2017-02-16 09:47:31 +0000 |
commit | aabe46b7c8c0f9da0079b71a1eb350536961bc3f (patch) | |
tree | 39fb19e2d44158549869c4fe305c6058e4ec8abc /mdoc_macro.c | |
parent | 873dc9b1d77212924c035df9c1accfbb3a4a6a7e (diff) | |
download | mandoc-aabe46b7c8c0f9da0079b71a1eb350536961bc3f.tar.gz mandoc-aabe46b7c8c0f9da0079b71a1eb350536961bc3f.tar.zst mandoc-aabe46b7c8c0f9da0079b71a1eb350536961bc3f.zip |
Fix block scoping error if an explicit block is broken by two
implicit blocks (.Aq Bq Po .Pc) that left the outer breaker open
and could in exceptional cases, like between .Bl and .It, cause
tree corruption leading to NULL dereference.
Found by tb@ with afl(1).
While here, do not mark intermediate ENDBODY markers as broken.
Diffstat (limited to 'mdoc_macro.c')
-rw-r--r-- | mdoc_macro.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/mdoc_macro.c b/mdoc_macro.c index a7ec6739..5ab9c412 100644 --- a/mdoc_macro.c +++ b/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.216 2017/02/16 03:00:23 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.217 2017/02/16 09:47:31 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org> @@ -381,6 +381,10 @@ rew_elem(struct roff_man *mdoc, int tok) static void break_intermediate(struct roff_node *n, struct roff_node *breaker) { + if (n != breaker && + n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD && + (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) + n = n->parent; while (n != breaker) { if ( ! (n->flags & NODE_VALID)) n->flags |= NODE_BROKEN; @@ -410,8 +414,7 @@ find_pending(struct roff_man *mdoc, int tok, int line, int ppos, if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { irc = 1; - break_intermediate(mdoc->last, n); - n->flags |= NODE_BROKEN; + break_intermediate(mdoc->last, target); if (target->type == ROFFT_HEAD) target->flags |= NODE_ENDED; else if ( ! (target->flags & NODE_ENDED)) { |