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.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
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);