Skip to content

Commit 98a2544

Browse files
committed
Merge branch 'fix-footnotes-nested-linkrefs-autolinker' into fix-footnotes-plus-fix-fnref-label-and-backrefs
2 parents 32002ec + a1d171a commit 98a2544

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

src/blocks.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ static void process_footnotes(cmark_parser *parser) {
532532
}
533533
}
534534

535+
cmark_unlink_footnotes_map(map);
535536
cmark_map_free(map);
536537
}
537538

src/footnotes.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,26 @@ void cmark_footnote_create(cmark_map *map, cmark_node *node) {
3838
cmark_map *cmark_footnote_map_new(cmark_mem *mem) {
3939
return cmark_map_new(mem, footnote_free);
4040
}
41+
42+
// Before calling `cmark_map_free` on a map with `cmark_footnotes`, first
43+
// unlink all of the footnote nodes before freeing their memory.
44+
//
45+
// Sometimes, two (unused) footnote nodes can end up referencing each other,
46+
// which as they get freed up by calling `cmark_map_free` -> `footnote_free` ->
47+
// etc, can lead to a use-after-free error.
48+
//
49+
// Better to `unlink` every footnote node first, setting their next, prev, and
50+
// parent pointers to NULL, and only then walk thru & free them up.
51+
void cmark_unlink_footnotes_map(cmark_map *map) {
52+
cmark_map_entry *ref;
53+
cmark_map_entry *next;
54+
55+
ref = map->refs;
56+
while(ref) {
57+
next = ref->next;
58+
if (((cmark_footnote *)ref)->node) {
59+
cmark_node_unlink(((cmark_footnote *)ref)->node);
60+
}
61+
ref = next;
62+
}
63+
}

src/footnotes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ typedef struct cmark_footnote cmark_footnote;
1818
void cmark_footnote_create(cmark_map *map, cmark_node *node);
1919
cmark_map *cmark_footnote_map_new(cmark_mem *mem);
2020

21+
void cmark_unlink_footnotes_map(cmark_map *map);
22+
2123
#ifdef __cplusplus
2224
}
2325
#endif

src/inlines.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,7 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
11781178
// being replacing the opening '[' text node with a `^footnote-ref]` node.
11791179
cmark_node_insert_before(opener->inl_text, fnref);
11801180

1181+
process_emphasis(parser, subj, opener->previous_delimiter);
11811182
// sometimes, the footnote reference text gets parsed into multiple nodes
11821183
// i.e. '[^example]' parsed into '[', '^exam', 'ple]'.
11831184
// this happens for ex with the autolink extension. when the autolinker
@@ -1200,7 +1201,7 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
12001201
}
12011202

12021203
cmark_node_free(opener->inl_text);
1203-
process_emphasis(parser, subj, opener->previous_delimiter);
1204+
12041205
pop_bracket(subj);
12051206
return NULL;
12061207
}

test/regression.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,30 @@ It has another footnote that contains many different characters (the autolinker
338338
</ol>
339339
</section>
340340
````````````````````````````````
341+
342+
Footnotes interacting with strikethrough should not lead to a use-after-free
343+
344+
```````````````````````````````` example footnotes autolink strikethrough table
345+
|Tot.....[^_a_]|
346+
.
347+
<p>|Tot.....[^_a_]|</p>
348+
````````````````````````````````
349+
350+
Footnotes interacting with strikethrough should not lead to a use-after-free pt2
351+
352+
```````````````````````````````` example footnotes autolink strikethrough table
353+
[^~~is~~1]
354+
.
355+
<p>[^~~is~~1]</p>
356+
````````````````````````````````
357+
358+
Adjacent unused footnotes definitions should not lead to a use after free
359+
360+
```````````````````````````````` example footnotes autolink strikethrough table
361+
Hello world
362+
363+
364+
[^a]:[^b]:
365+
.
366+
<p>Hello world</p>
367+
````````````````````````````````

0 commit comments

Comments
 (0)