summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2011-09-18 23:51:31 +0000
committerIngo Schwarze <schwarze@openbsd.org>2011-09-18 23:51:31 +0000
commit42c0d6412f67fc0af50b2f3219644a1adbe028f2 (patch)
tree47fa7cc5fe24b41de98bf56526852d2f0228079c
parent28dc1d2e4d1a3234ff9bda014276f222295dbc35 (diff)
downloadmandoc-42c0d6412f67fc0af50b2f3219644a1adbe028f2.tar.gz
mandoc-42c0d6412f67fc0af50b2f3219644a1adbe028f2.tar.zst
mandoc-42c0d6412f67fc0af50b2f3219644a1adbe028f2.zip
Fix another regression introduced in 1.11.7:
If a string is defined in terms of itself, the REPARSE_LIMIT in read.c used to break the cycle. This no longer works since all the work is now done in the function roff_res(), looping indefinitely. Make this loop finite by arbitrarily limiting the number of times one string may be expanded; when that limit is reached, leave the remaining string references unexpanded. This changes behaviour compared to 1.11.5, where the whole line would have been dropped. The new behaviour is better because it loses less information. We don't want to imitate groff-1.20.1 behaviour anyway because groff aborts parsing of the whole file. ok kristaps@
-rw-r--r--roff.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/roff.c b/roff.c
index 67319317..18b7aa65 100644
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.169 2011/09/18 14:14:15 schwarze Exp $ */
+/* $Id: roff.c,v 1.170 2011/09/18 23:51:31 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -31,6 +31,9 @@
/* Maximum number of nested if-else conditionals. */
#define RSTACK_MAX 128
+/* Maximum number of string expansions per line, to break infinite loops. */
+#define EXPAND_LIMIT 1000
+
enum rofft {
ROFF_ad,
ROFF_am,
@@ -437,10 +440,12 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
const char *res; /* the string to be substituted */
- int i, maxl;
+ int i, maxl, expand_count;
size_t nsz;
char *n;
+ expand_count = 0;
+
again:
cp = *bufp + pos;
while (NULL != (cp = strchr(cp, '\\'))) {
@@ -535,7 +540,13 @@ again:
*bufp = n;
*szp = nsz;
- goto again;
+
+ if (EXPAND_LIMIT >= ++expand_count)
+ goto again;
+
+ /* Just leave the string unexpanded. */
+ mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
+ return;
}
}