From 2ae87732d9ac0461901b8d550dfb594b6ec4ebe8 Mon Sep 17 00:00:00 2001 From: jessica parsons Date: Tue, 16 Jun 2026 01:54:15 -0700 Subject: [PATCH] add code to do maximum recursion depth, and default it to 200 --- Makefile.in | 7 ++++++- configure.sh | 6 ++++++ generate.c | 4 +++- markdown.c | 8 +++++++- markdown.h | 1 + tests/limits.t | 29 +++++++++++++++++++++++++++++ tools/300.c | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 tests/limits.t create mode 100644 tools/300.c 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'); +}