- Commit
- ade396db95e2fcfef4d1769850f4a322e175981b
- Parent
- 2994011ce13f3a437c637dcac6bc841b22d80b6c
- Author
- Nick Wellnhofer <wellnhofer@aevum.de>
- Date
Fix quadratic behavior when parsing inlines
The inline parsing code would call cmark_node_append_child to append
nodes. This public function has a sanity check which is linear in the
depth of the tree. Repeated calls could show quadratic behavior in
degenerate trees. Use a special function to append nodes without this
check.
Fixes #373. Found by OSS-Fuzz.
diff --git a/src/inlines.c b/src/inlines.c
@@ -129,6 +129,24 @@ static cmark_node *make_str_with_entities(subject *subj,
}
}
+// Like cmark_node_append_child but without costly sanity checks.
+// Assumes that child was newly created.
+static void append_child(cmark_node *node, cmark_node *child) {
+ cmark_node *old_last_child = node->last_child;
+
+ child->next = NULL;
+ child->prev = old_last_child;
+ child->parent = node;
+ node->last_child = child;
+
+ if (old_last_child) {
+ old_last_child->next = child;
+ } else {
+ // Also set first_child if node previously had no children.
+ node->first_child = child;
+ }
+}
+
// Duplicate a chunk by creating a copy of the buffer not by reusing the
// buffer like cmark_chunk_dup does.
static unsigned char *cmark_strdup(cmark_mem *mem, unsigned char *src) {
@@ -163,7 +181,7 @@ static CMARK_INLINE cmark_node *make_autolink(subject *subj,
link->start_line = link->end_line = subj->line;
link->start_column = start_column + 1;
link->end_column = end_column + 1;
- cmark_node_append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
+ append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
return link;
}
@@ -741,7 +759,8 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
tmp = opener_inl->next;
while (tmp && tmp != closer_inl) {
tmpnext = tmp->next;
- cmark_node_append_child(emph, tmp);
+ cmark_node_unlink(tmp);
+ append_child(emph, tmp);
tmp = tmpnext;
}
cmark_node_insert_after(opener_inl, emph);
@@ -1121,7 +1140,8 @@ match:
tmp = opener->inl_text->next;
while (tmp) {
tmpnext = tmp->next;
- cmark_node_append_child(inl, tmp);
+ cmark_node_unlink(tmp);
+ append_child(inl, tmp);
tmp = tmpnext;
}
@@ -1289,7 +1309,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
new_inl = make_str(subj, startpos, endpos - 1, contents);
}
if (new_inl != NULL) {
- cmark_node_append_child(parent, new_inl);
+ append_child(parent, new_inl);
}
return 1;