Limit length of code span marks to lower then 256 characters. This protects against a pathologic case generated by $ python -c 'print( "".join(map(lambda x: ("e" + "`" * x), range(1,10000))))'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
diff --git a/md4c/md4c.c b/md4c/md4c.c
index aa13562..a666295 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -2286,18 +2286,25 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
/* A potential code span start/end. */
if(ch == _T('`')) {
- unsigned flags;
OFF tmp = off+1;
- /* It may be opener only if it is not escaped. */
- if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].beg == off-1 && CH(off-1) == _T('\\'))
- flags = MD_MARK_POTENTIAL_CLOSER;
- else
- flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER;
-
while(tmp < line_end && CH(tmp) == _T('`'))
tmp++;
- PUSH_MARK(ch, off, tmp, flags);
+
+ /* We limit code span marks to lower then 256 backticks. This
+ * solves a pathologic case of too many openers, each of
+ * different length: Their resolving is then O(n^2). */
+ if(tmp - off < 256) {
+ unsigned flags;
+
+ /* It may be opener only if it is not escaped. */
+ if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].beg == off-1 && CH(off-1) == _T('\\'))
+ flags = MD_MARK_POTENTIAL_CLOSER;
+ else
+ flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER;
+
+ PUSH_MARK(ch, off, tmp, flags);
+ }
off = tmp;
continue;