cmark

My personal build of CMark ✏️

Commit
9305d14f39f72c1ad02917df7e15126dc4a4ab1c
Parent
56501dc4d3f8d33c13ca833d2386a445ecde7435
Author
John MacFarlane <jgm@berkeley.edu>
Date

Fixed get_containing_block logic in src/commonmark.c.

This did not allow for the possibility that a node might have no containing block, causing the commonmark renderer to segfault if passed an inline node with no block parent.

Diffstat

2 files changed, 14 insertions, 9 deletions

Status File Name N° Changes Insertions Deletions
Modified api_test/main.c 1 0 1
Modified src/commonmark.c 22 14 8
diff --git a/api_test/main.c b/api_test/main.c
@@ -675,7 +675,6 @@ static void render_commonmark(test_batch_runner *runner) {
          "render document without wrapping");
   free(commonmark);
 
-  /* TODO segfaults */
   cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
   cmark_node_set_literal(text, "Hi");
   commonmark = cmark_render_commonmark(text, CMARK_OPT_DEFAULT, 0);
diff --git a/src/commonmark.c b/src/commonmark.c
@@ -135,12 +135,17 @@ static bool is_autolink(cmark_node *node) {
 
 // if node is a block node, returns node.
 // otherwise returns first block-level node that is an ancestor of node.
+// if there is no block-level ancestor, returns NULL.
 static cmark_node *get_containing_block(cmark_node *node) {
-  while (node && (node->type < CMARK_NODE_FIRST_BLOCK ||
-                  node->type > CMARK_NODE_LAST_BLOCK)) {
-    node = node->parent;
+  while (node) {
+    if (node->type >= CMARK_NODE_FIRST_BLOCK &&
+        node->type <= CMARK_NODE_LAST_BLOCK) {
+      return node;
+    } else {
+      node = node->parent;
+    }
   }
-  return node;
+  return NULL;
 }
 
 static int S_render_node(cmark_renderer *renderer, cmark_node *node,
@@ -163,10 +168,11 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
   if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
     tmp = get_containing_block(node);
     renderer->in_tight_list_item =
-        (tmp->type == CMARK_NODE_ITEM &&
-         cmark_node_get_list_tight(tmp->parent)) ||
-        (tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
-         cmark_node_get_list_tight(tmp->parent->parent));
+	tmp &&  // tmp might be NULL if there is no containing block
+        ((tmp->type == CMARK_NODE_ITEM &&
+          cmark_node_get_list_tight(tmp->parent)) ||
+         (tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
+          cmark_node_get_list_tight(tmp->parent->parent)));
   }
 
   switch (node->type) {