Commit 2a70b3efa199ccb5616d41c611d5c7cadf926b6a

Martin Mitas 2016-11-26T20:32:33

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))))'

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;