summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2010-12-10 20:58:56 +0000
committerIngo Schwarze <schwarze@openbsd.org>2010-12-10 20:58:56 +0000
commit5086d878fd97d26b928c5a38d9e1c5dba788cf4a (patch)
tree265018173abe1a7d4bd48a1e847990309a8482be
parent0ea3458e9a7b752653b5397bb21ee0977a4b77ab (diff)
downloadmandoc-5086d878fd97d26b928c5a38d9e1c5dba788cf4a.tar.gz
Abort endless loops during roff macro and string expansion.
For now, use the simplest conceivable approach, like groff does: Just a fixed, ugly input stack limit. "check it in" kristaps@
-rw-r--r--main.c13
-rw-r--r--mandoc.h1
-rw-r--r--roff.76
3 files changed, 18 insertions, 2 deletions
diff --git a/main.c b/main.c
index 4bf39c3c..e2e7f04f 100644
--- a/main.c
+++ b/main.c
@@ -41,6 +41,7 @@
#define MAP_FILE 0
#endif
+#define REPARSE_LIMIT 1000
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
/* FIXME: Intel's compiler? LLVM? pcc? */
@@ -89,6 +90,7 @@ struct curparse {
struct mdoc *mdoc; /* mdoc parser */
struct roff *roff; /* roff parser (!NULL) */
struct regset regs; /* roff registers */
+ int reparse_count; /* finite interpolation stack */
enum outt outtype; /* which output to use */
out_mdoc outmdoc; /* mdoc output ptr */
out_man outman; /* man output ptr */
@@ -177,6 +179,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"generic error",
+ "input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping text before the first section header",
"skipping unknown macro",
@@ -665,8 +668,10 @@ parsebuf(struct curparse *curp, struct buf blk, int start)
if (0 == pos && '\0' == blk.buf[i])
break;
- if (start)
+ if (start) {
curp->line = lnn;
+ curp->reparse_count = 0;
+ }
while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
if ('\n' == blk.buf[i]) {
@@ -765,7 +770,11 @@ rerun:
switch (rr) {
case (ROFF_REPARSE):
- parsebuf(curp, ln, 0);
+ if (REPARSE_LIMIT >= ++curp->reparse_count)
+ parsebuf(curp, ln, 0);
+ else
+ mmsg(MANDOCERR_ROFFLOOP, curp,
+ curp->line, pos, NULL);
pos = 0;
continue;
case (ROFF_APPEND):
diff --git a/mandoc.h b/mandoc.h
index 041b004f..58c339fd 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -101,6 +101,7 @@ enum mandocerr {
MANDOCERR_ERROR, /* ===== start of errors ===== */
+ MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_BADCHAR, /* skipping bad character */
MANDOCERR_NOTEXT, /* skipping text before the first section header */
MANDOCERR_MACRO, /* skipping unknown macro */
diff --git a/roff.7 b/roff.7
index 2f007718..a29d6a92 100644
--- a/roff.7
+++ b/roff.7
@@ -196,6 +196,12 @@ string interpolation syntax described below
.Sx ds ,
but this is rarely useful because every macro definition contains at least
one explicit newline character.
+.Pp
+In order to prevent endless recursion, both groff and
+.Xr mandoc 1
+limit the stack depth for expanding macros and strings
+to a large, but finite number.
+Do not rely on the exact value of this limit.
.Ss \&dei
Define a user-defined
.Nm