diff --git a/Makefile.in b/Makefile.in
index 69c284e..6d07afb 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,7 +31,7 @@ OBJS=mkdio.o markdown.o dumptree.o generate.o \
github_flavoured.o setup.o tags.o html5.o \
pgm_options.o flags.o v2compat.o flagprocs.o \
@AMALLOC@ @H1TITLE@
-TESTFRAMEWORK=rep echo cols branch pandoc_headers space2nl
+TESTFRAMEWORK=300 rep echo cols branch pandoc_headers space2nl
# modules that markdown, makepage, mkd2html, &tc use
COMMON=gethopt.o notspecial.o
@@ -152,6 +152,11 @@ rep.o : tools/rep.c
rep: rep.o
$(LINK) -o rep rep.o
+300.o : tools/300.c
+ $(BUILD) -c -o 300.o tools/300.c
+300: 300.o
+ $(LINK) -o 300 300.o
+
branch.o: tools/branch.c config.h
$(BUILD) -c -o branch.o tools/branch.c
branch: branch.o
diff --git a/configure.sh b/configure.sh
index 2f2c1c8..226631b 100755
--- a/configure.sh
+++ b/configure.sh
@@ -13,6 +13,7 @@ ac_help='--enable-amalloc Enable memory allocation debugging
--container Build inside a container
--pkg-config Install pkg-config(1) glue files
--cxx-binding Install header files with c++ wrappers
+--with-recursion=NNN how deeply things can nest before the become just text
--github-checkbox[=input] Enable github-style checkboxes in lists
(if =input, use , otherwise
use html ballot entities)'
@@ -238,6 +239,11 @@ else
AC_SUB 'THEME' '#'
fi
+if [ -z "$WITH_RECURSION" ]; then
+ WITH_RECURSION=200
+fi
+AC_DEFINE 'MAX_RECURSION' $WITH_RECURSION
+
if [ -z "$WITH_TABSTOPS" ]; then
TABSTOP=4
elif [ "$WITH_TABSTOPS" -eq 1 ]; then
diff --git a/generate.c b/generate.c
index 5ec1c5b..29de73c 100644
--- a/generate.c
+++ b/generate.c
@@ -235,6 +235,7 @@ ___mkd_reparse(char *bfr, int size, mkd_flag_t* flags, MMIOT *f, char *esc)
pushc(0, &sub);
S(sub.in)--;
+ sub.recursion = f->recursion+1;
text(&sub);
___mkd_emblock(&sub);
@@ -1476,7 +1477,8 @@ text(MMIOT *f)
|| (f->last == 0)
|| ((ispunct(f->last) || isspace(f->last))
&& f->last != ')')
- || isthisspace(f,1) )
+ || isthisspace(f,1)
+ || f->recursion > MAX_RECURSION )
Qchar(c,f);
else {
char *sup = cursor(f);
diff --git a/markdown.c b/markdown.c
index 0e2b615..2cb0766 100644
--- a/markdown.c
+++ b/markdown.c
@@ -1434,9 +1434,14 @@ compile(Line *ptr, int toplevel, MMIOT *f)
ptr = consume(ptr, ¶);
+ ++(f->recursion);
while ( ptr ) {
- if ( iscode(ptr) ) {
+ if ( f->recursion > MAX_RECURSION ) {
+ p = Pp(&d, ptr, MARKUP);
+ ptr = textblock(p, toplevel, &(f->flags) );
+ }
+ else if ( iscode(ptr) ) {
p = Pp(&d, ptr, CODE);
if ( is_flag_set(&(f->flags), MKD_1_COMPAT) ) {
@@ -1530,6 +1535,7 @@ compile(Line *ptr, int toplevel, MMIOT *f)
p->align = PARA;
}
+ (f->recursion)--;
return T(d);
}
diff --git a/markdown.h b/markdown.h
index 04d4af6..e7845b8 100644
--- a/markdown.h
+++ b/markdown.h
@@ -196,6 +196,7 @@ typedef struct mmiot {
Qblock Q;
char last; /* last text character added to out */
int isp;
+ int recursion;
struct escaped *esc;
char *ref_prefix;
struct footnote_list *footnotes;
diff --git a/tests/limits.t b/tests/limits.t
new file mode 100644
index 0000000..c734d2d
--- /dev/null
+++ b/tests/limits.t
@@ -0,0 +1,29 @@
+. tests/functions.sh
+
+title 'Recursion limits'
+rc=0
+
+limits() {
+ try_header "$1"
+
+ res=`./300 400 $3 $4 $5 | ./markdown | tr -dc "$2" | wc -c`
+
+ if (( $res > 0 )); then
+ # it worked
+ test $VERBOSE && ./echo " ok"
+ else
+ test "$VERBOSE" && ./echo "failed"
+ rc=1
+ fi
+
+}
+
+
+limits "superscripts" "()" "2^(" "A" ")"
+
+limits "list items" "1" "1. " "item"
+
+limits "blockquotes" ">" "> " "item"
+
+summary $0
+exit $rc
diff --git a/tools/300.c b/tools/300.c
new file mode 100644
index 0000000..c184a57
--- /dev/null
+++ b/tools/300.c
@@ -0,0 +1,36 @@
+#include
+#include
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int reps;
+ int i;
+ char *pattern1, *text = NULL, *pattern2 = NULL;
+
+ if ( argc < 3 ) {
+ fprintf(stderr, "usage: 300 reps pattern1 [text [pattern2]]\n");
+ exit(1);
+ }
+
+
+ reps = atoi(argv[1]);
+ pattern1 = argv[2];
+ if ( argc > 3 )
+ text = argv[3];
+ if ( argc > 4 )
+ pattern2 = argv[4];
+
+ for ( i=0; i < reps; i++ )
+ printf("%s", pattern1);
+
+ if ( text )
+ printf(" %s ", text);
+
+ if ( pattern2 )
+ for ( i=0; i < reps; i++ )
+ printf("%s", pattern2);
+
+ putchar('\n');
+}