Commit 035dea495b814709eea8cfbea7cc4589d0a3c0f8

Martin Mitas 2016-12-04T20:48:06

Fix crash caused by bad management of opener chains. 1. We need to reset (potentially used) chains after each mark analysis phase. This ensures that md_rollback() does not try to play with chains used in previous phases. 2. md_rollback() must never play with PTR_CHAIN.

diff --git a/md4c/md4c.c b/md4c/md4c.c
index 0f94d6e..2fd2963 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -2074,8 +2074,9 @@ md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how)
     int i;
     int mark_index;
 
-    /* Cut all unresolved openers at the mark index. */
-    for(i = 0; i < SIZEOF_ARRAY(ctx->mark_chains); i++) {
+    /* Cut all unresolved openers at the mark index. 
+     * (start at 1 to not touch PTR_CHAIN.) */
+    for(i = 1; i < SIZEOF_ARRAY(ctx->mark_chains); i++) {
         MD_MARKCHAIN* chain = &ctx->mark_chains[i];
 
         while(chain->tail >= opener_index)
@@ -3151,7 +3152,6 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF en
 static int
 md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
 {
-    int i;
     int ret;
     OFF beg = lines[0].beg;
     OFF end = lines[n_lines-1].end;
@@ -3159,14 +3159,6 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
     /* Reset the previously collected stack of marks. */
     ctx->n_marks = 0;
 
-    /* Reset all unresolved opener mark chains. */
-    for(i = 0; i < SIZEOF_ARRAY(ctx->mark_chains); i++) {
-        ctx->mark_chains[i].head = -1;
-        ctx->mark_chains[i].tail = -1;
-    }
-    ctx->unresolved_link_head = -1;
-    ctx->unresolved_link_tail = -1;
-
     /* Collect all marks. */
     if(md_collect_marks(ctx, lines, n_lines) != 0)
         return -1;
@@ -3174,11 +3166,23 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
     /* We analyze marks in few groups to handle their precedence. */
     /* (1) Entities; code spans; autolinks; raw HTML. */
     md_analyze_marks(ctx, lines, n_lines, beg, end, _T("&`<>"));
+    BACKTICK_OPENERS.head = -1;
+    BACKTICK_OPENERS.tail = -1;
+    LOWERTHEN_OPENERS.head = -1;
+    LOWERTHEN_OPENERS.tail = -1;
     /* (2) Links. */
     md_analyze_marks(ctx, lines, n_lines, beg, end, _T("[]!"));
     MD_CHECK(md_resolve_links(ctx, lines, n_lines));
+    BRACKET_OPENERS.head = -1;
+    BRACKET_OPENERS.tail = -1;
+    ctx->unresolved_link_head = -1;
+    ctx->unresolved_link_tail = -1;
     /* (3) Emphasis and strong emphasis; permissive autolinks. */
     md_analyze_marks(ctx, lines, n_lines, beg, end, _T("*_@:"));
+    ASTERISK_OPENERS.head = -1;
+    ASTERISK_OPENERS.tail = -1;
+    UNDERSCORE_OPENERS.head = -1;
+    UNDERSCORE_OPENERS.tail = -1;
 
 abort:
     return ret;
@@ -3188,8 +3192,6 @@ static void
 md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF end)
 {
     md_analyze_marks(ctx, lines, n_lines, beg, end, _T("*_@:"));
-
-    /* Reset the chains we could use. */
     ASTERISK_OPENERS.head = -1;
     ASTERISK_OPENERS.tail = -1;
     UNDERSCORE_OPENERS.head = -1;
@@ -3703,6 +3705,8 @@ abort:
     /* Free any temporary memory blocks stored within some dummy marks. */
     for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next)
         free(md_mark_get_ptr(ctx, i));
+    PTR_CHAIN.head = -1;
+    PTR_CHAIN.tail = -1;
 
     return ret;
 }
@@ -5216,6 +5220,7 @@ int
 md_parse(const MD_CHAR* text, MD_SIZE size, const MD_RENDERER* renderer, void* userdata)
 {
     MD_CTX ctx;
+    int i;
     int ret;
 
     /* Setup context structure. */
@@ -5227,6 +5232,14 @@ md_parse(const MD_CHAR* text, MD_SIZE size, const MD_RENDERER* renderer, void* u
     ctx.code_indent_offset = (ctx.r.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4;
     md_build_mark_char_map(&ctx);
 
+    /* Reset all unresolved opener mark chains. */
+    for(i = 0; i < SIZEOF_ARRAY(ctx.mark_chains); i++) {
+        ctx.mark_chains[i].head = -1;
+        ctx.mark_chains[i].tail = -1;
+    }
+    ctx.unresolved_link_head = -1;
+    ctx.unresolved_link_tail = -1;
+
     /* All the work. */
     ret = md_process_doc(&ctx);