md4c

C Markdown parser. Fast. SAX-like interface. Compliant to CommonMark specification.
git clone https://noulin.net/git/md4c.git
Log | Files | Refs | README | LICENSE

commit 035dea495b814709eea8cfbea7cc4589d0a3c0f8
parent 578dea5b81474bb16ac66cf79cf876c5e8be77bf
Author: Martin Mitas <mity@morous.org>
Date:   Sun,  4 Dec 2016 20:48:06 +0100

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.

Diffstat:
Mmd4c/md4c.c | 39++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)

diff --git 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);