summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xCMakeLists.txt1
-rw-r--r--Makefile10
-rw-r--r--README.md8
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/latex.c4
-rw-r--r--test/afl_dictionary/asterisk1
-rw-r--r--test/afl_dictionary/attr_generic1
-rw-r--r--test/afl_dictionary/attr_href1
-rw-r--r--test/afl_dictionary/attr_xml_lang1
-rw-r--r--test/afl_dictionary/attr_xmlns1
-rw-r--r--test/afl_dictionary/backslash1
-rw-r--r--test/afl_dictionary/backtick1
-rw-r--r--test/afl_dictionary/colon1
-rw-r--r--test/afl_dictionary/dashes1
-rw-r--r--test/afl_dictionary/double_quote1
-rw-r--r--test/afl_dictionary/entity_builtin1
-rw-r--r--test/afl_dictionary/entity_decimal1
-rw-r--r--test/afl_dictionary/entity_external1
-rw-r--r--test/afl_dictionary/entity_hex1
-rw-r--r--test/afl_dictionary/equals1
-rw-r--r--test/afl_dictionary/exclamation1
-rw-r--r--test/afl_dictionary/greater_than1
-rw-r--r--test/afl_dictionary/hash1
-rw-r--r--test/afl_dictionary/hyphen0
-rw-r--r--test/afl_dictionary/indent1
-rw-r--r--test/afl_dictionary/left_bracket1
-rw-r--r--test/afl_dictionary/left_paren1
-rw-r--r--test/afl_dictionary/less_than1
-rw-r--r--test/afl_dictionary/plus1
-rw-r--r--test/afl_dictionary/right_bracket1
-rw-r--r--test/afl_dictionary/right_paren1
-rw-r--r--test/afl_dictionary/single_quote1
-rw-r--r--test/afl_dictionary/string_any1
-rw-r--r--test/afl_dictionary/string_brackets1
-rw-r--r--test/afl_dictionary/string_cdata1
-rw-r--r--test/afl_dictionary/string_dashes1
-rw-r--r--test/afl_dictionary/string_empty_dblquotes1
-rw-r--r--test/afl_dictionary/string_empty_quotes1
-rw-r--r--test/afl_dictionary/string_idrefs1
-rw-r--r--test/afl_dictionary/string_parentheses1
-rw-r--r--test/afl_dictionary/string_pcdata1
-rw-r--r--test/afl_dictionary/tag_cdata1
-rw-r--r--test/afl_dictionary/tag_close1
-rw-r--r--test/afl_dictionary/tag_doctype1
-rw-r--r--test/afl_dictionary/tag_element1
-rw-r--r--test/afl_dictionary/tag_entity1
-rw-r--r--test/afl_dictionary/tag_notation1
-rw-r--r--test/afl_dictionary/tag_open1
-rw-r--r--test/afl_dictionary/tag_open_close1
-rw-r--r--test/afl_dictionary/tag_open_exclamation1
-rw-r--r--test/afl_dictionary/tag_open_q1
-rw-r--r--test/afl_dictionary/tag_sq2_close1
-rw-r--r--test/afl_dictionary/tag_xml_q1
-rw-r--r--test/afl_dictionary/underscore1
-rw-r--r--test/cmark-fuzz.c28
-rw-r--r--test/fuzzing_dictionary49
-rwxr-xr-xtest/run-cmark-fuzz4
57 files changed, 114 insertions, 49 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4e60fd5..33180e5 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@ set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
option(CMARK_TESTS "Build cmark tests and enable testing" ON)
option(CMARK_STATIC "Build static libcmark library" ON)
option(CMARK_SHARED "Build shared libcmark library" ON)
+option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF)
add_subdirectory(src)
if(CMARK_TESTS AND CMARK_SHARED)
diff --git a/Makefile b/Makefile
index 987ed2b..c10c035 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ BENCHFILE=$(BENCHDIR)/benchinput.md
ALLTESTS=alltests.md
NUMRUNS?=10
CMARK=$(BUILDDIR)/src/cmark
+CMARK_FUZZ=$(BUILDDIR)/src/cmark-fuzz
PROG?=$(CMARK)
VERSION?=$(SPECVERSION)
RELEASE?=CommonMark-$(VERSION)
@@ -77,10 +78,17 @@ afl:
$(AFL_PATH)/afl-fuzz \
-i test/afl_test_cases \
-o test/afl_results \
- -x test/afl_dictionary \
+ -x test/fuzzing_dictionary \
-t 100 \
$(CMARK) $(CMARK_OPTS)
+libFuzzer:
+ @[ -n "$(LIB_FUZZER_PATH)" ] || { echo '$$LIB_FUZZER_PATH not set'; false; }
+ mkdir -p $(BUILDDIR)
+ cd $(BUILDDIR) && cmake -DCMAKE_BUILD_TYPE=Asan -DCMARK_LIB_FUZZER=ON -DCMAKE_LIB_FUZZER_PATH=$(LIB_FUZZER_PATH) ..
+ $(MAKE) -j2 -C $(BUILDDIR) cmark-fuzz
+ test/run-cmark-fuzz $(CMARK_FUZZ)
+
clang-check: all
${CLANG_CHECK} -p build -analyze src/*.c
diff --git a/README.md b/README.md
index 9aaf32f..1c9dd69 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,13 @@ To do a more systematic fuzz test with [american fuzzy lop]:
AFL_PATH=/path/to/afl_directory make afl
+Fuzzing with [libFuzzer] is also supported but, because libFuzzer is still
+under active development, may not work with your system-installed version of
+clang. Assuming LLVM has been built in `$HOME/src/llvm/build` the fuzzer can be
+run with:
+
+ CC="$HOME/src/llvm/build/bin/clang" LIB_FUZZER_PATH="$HOME/src/llvm/lib/Fuzzer/libFuzzer.a" make libFuzzer
+
To make a release tarball and zip archive:
make archive
@@ -188,3 +195,4 @@ most of the C library's API and its test harness.
[Build Status]: https://img.shields.io/travis/jgm/cmark/master.svg?style=flat
[Windows Build Status]: https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true
[american fuzzy lop]: http://lcamtuf.coredump.cx/afl/
+[libFuzzer]: http://llvm.org/docs/LibFuzzer.html
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f52ded6..3197196 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -186,3 +186,14 @@ endif()
if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
endif()
+
+if(CMARK_LIB_FUZZER)
+ set(FUZZ_HARNESS "cmark-fuzz")
+ add_executable(${FUZZ_HARNESS} ../test/cmark-fuzz.c ${LIBRARY_SOURCES})
+ target_link_libraries(${FUZZ_HARNESS} "${CMAKE_LIB_FUZZER_PATH}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-coverage=trace-pc-guard")
+
+ # cmark is written in C but the libFuzzer runtime is written in C++ which
+ # needs to link against the C++ runtime. Explicitly link it into cmark-fuzz
+ set_target_properties(${FUZZ_HARNESS} PROPERTIES LINK_FLAGS "-lstdc++")
+endif()
diff --git a/src/latex.c b/src/latex.c
index 9bd6444..22052d7 100644
--- a/src/latex.c
+++ b/src/latex.c
@@ -179,6 +179,10 @@ static link_type get_link_type(cmark_node *node) {
link_text = node->first_child;
cmark_consolidate_text_nodes(link_text);
+
+ if (!link_text)
+ return NO_LINK;
+
realurl = (char *)url;
realurllen = (int)url_len;
if (strncmp(realurl, "mailto:", 7) == 0) {
diff --git a/test/afl_dictionary/asterisk b/test/afl_dictionary/asterisk
deleted file mode 100644
index f59ec20..0000000
--- a/test/afl_dictionary/asterisk
+++ /dev/null
@@ -1 +0,0 @@
-* \ No newline at end of file
diff --git a/test/afl_dictionary/attr_generic b/test/afl_dictionary/attr_generic
deleted file mode 100644
index d84e4b2..0000000
--- a/test/afl_dictionary/attr_generic
+++ /dev/null
@@ -1 +0,0 @@
- a="1" \ No newline at end of file
diff --git a/test/afl_dictionary/attr_href b/test/afl_dictionary/attr_href
deleted file mode 100644
index cbb9775..0000000
--- a/test/afl_dictionary/attr_href
+++ /dev/null
@@ -1 +0,0 @@
- href="1" \ No newline at end of file
diff --git a/test/afl_dictionary/attr_xml_lang b/test/afl_dictionary/attr_xml_lang
deleted file mode 100644
index 6dab3e9..0000000
--- a/test/afl_dictionary/attr_xml_lang
+++ /dev/null
@@ -1 +0,0 @@
- xml:lang="1" \ No newline at end of file
diff --git a/test/afl_dictionary/attr_xmlns b/test/afl_dictionary/attr_xmlns
deleted file mode 100644
index 168863a..0000000
--- a/test/afl_dictionary/attr_xmlns
+++ /dev/null
@@ -1 +0,0 @@
- xmlns="1" \ No newline at end of file
diff --git a/test/afl_dictionary/backslash b/test/afl_dictionary/backslash
deleted file mode 100644
index b7d5379..0000000
--- a/test/afl_dictionary/backslash
+++ /dev/null
@@ -1 +0,0 @@
-\ \ No newline at end of file
diff --git a/test/afl_dictionary/backtick b/test/afl_dictionary/backtick
deleted file mode 100644
index 64845fb..0000000
--- a/test/afl_dictionary/backtick
+++ /dev/null
@@ -1 +0,0 @@
-` \ No newline at end of file
diff --git a/test/afl_dictionary/colon b/test/afl_dictionary/colon
deleted file mode 100644
index 22ded55..0000000
--- a/test/afl_dictionary/colon
+++ /dev/null
@@ -1 +0,0 @@
-: \ No newline at end of file
diff --git a/test/afl_dictionary/dashes b/test/afl_dictionary/dashes
deleted file mode 100644
index 73b314f..0000000
--- a/test/afl_dictionary/dashes
+++ /dev/null
@@ -1 +0,0 @@
---- \ No newline at end of file
diff --git a/test/afl_dictionary/double_quote b/test/afl_dictionary/double_quote
deleted file mode 100644
index 9d68933..0000000
--- a/test/afl_dictionary/double_quote
+++ /dev/null
@@ -1 +0,0 @@
-" \ No newline at end of file
diff --git a/test/afl_dictionary/entity_builtin b/test/afl_dictionary/entity_builtin
deleted file mode 100644
index 1489a83..0000000
--- a/test/afl_dictionary/entity_builtin
+++ /dev/null
@@ -1 +0,0 @@
-< \ No newline at end of file
diff --git a/test/afl_dictionary/entity_decimal b/test/afl_dictionary/entity_decimal
deleted file mode 100644
index 7b997f6..0000000
--- a/test/afl_dictionary/entity_decimal
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/test/afl_dictionary/entity_external b/test/afl_dictionary/entity_external
deleted file mode 100644
index f626a66..0000000
--- a/test/afl_dictionary/entity_external
+++ /dev/null
@@ -1 +0,0 @@
-&a; \ No newline at end of file
diff --git a/test/afl_dictionary/entity_hex b/test/afl_dictionary/entity_hex
deleted file mode 100644
index 8766028..0000000
--- a/test/afl_dictionary/entity_hex
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/test/afl_dictionary/equals b/test/afl_dictionary/equals
deleted file mode 100644
index 7193984..0000000
--- a/test/afl_dictionary/equals
+++ /dev/null
@@ -1 +0,0 @@
-=== \ No newline at end of file
diff --git a/test/afl_dictionary/exclamation b/test/afl_dictionary/exclamation
deleted file mode 100644
index 74e0f12..0000000
--- a/test/afl_dictionary/exclamation
+++ /dev/null
@@ -1 +0,0 @@
-! \ No newline at end of file
diff --git a/test/afl_dictionary/greater_than b/test/afl_dictionary/greater_than
deleted file mode 100644
index 0817502..0000000
--- a/test/afl_dictionary/greater_than
+++ /dev/null
@@ -1 +0,0 @@
-> \ No newline at end of file
diff --git a/test/afl_dictionary/hash b/test/afl_dictionary/hash
deleted file mode 100644
index 4287ca8..0000000
--- a/test/afl_dictionary/hash
+++ /dev/null
@@ -1 +0,0 @@
-# \ No newline at end of file
diff --git a/test/afl_dictionary/hyphen b/test/afl_dictionary/hyphen
deleted file mode 100644
index e69de29..0000000
--- a/test/afl_dictionary/hyphen
+++ /dev/null
diff --git a/test/afl_dictionary/indent b/test/afl_dictionary/indent
deleted file mode 100644
index 136d063..0000000
--- a/test/afl_dictionary/indent
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/test/afl_dictionary/left_bracket b/test/afl_dictionary/left_bracket
deleted file mode 100644
index 8e2f0be..0000000
--- a/test/afl_dictionary/left_bracket
+++ /dev/null
@@ -1 +0,0 @@
-[ \ No newline at end of file
diff --git a/test/afl_dictionary/left_paren b/test/afl_dictionary/left_paren
deleted file mode 100644
index f46d387..0000000
--- a/test/afl_dictionary/left_paren
+++ /dev/null
@@ -1 +0,0 @@
-( \ No newline at end of file
diff --git a/test/afl_dictionary/less_than b/test/afl_dictionary/less_than
deleted file mode 100644
index c5fa784..0000000
--- a/test/afl_dictionary/less_than
+++ /dev/null
@@ -1 +0,0 @@
-< \ No newline at end of file
diff --git a/test/afl_dictionary/plus b/test/afl_dictionary/plus
deleted file mode 100644
index 9b26e9b..0000000
--- a/test/afl_dictionary/plus
+++ /dev/null
@@ -1 +0,0 @@
-+ \ No newline at end of file
diff --git a/test/afl_dictionary/right_bracket b/test/afl_dictionary/right_bracket
deleted file mode 100644
index 54caf60..0000000
--- a/test/afl_dictionary/right_bracket
+++ /dev/null
@@ -1 +0,0 @@
-] \ No newline at end of file
diff --git a/test/afl_dictionary/right_paren b/test/afl_dictionary/right_paren
deleted file mode 100644
index e8a0f87..0000000
--- a/test/afl_dictionary/right_paren
+++ /dev/null
@@ -1 +0,0 @@
-) \ No newline at end of file
diff --git a/test/afl_dictionary/single_quote b/test/afl_dictionary/single_quote
deleted file mode 100644
index ad2823b..0000000
--- a/test/afl_dictionary/single_quote
+++ /dev/null
@@ -1 +0,0 @@
-' \ No newline at end of file
diff --git a/test/afl_dictionary/string_any b/test/afl_dictionary/string_any
deleted file mode 100644
index bcd7dd4..0000000
--- a/test/afl_dictionary/string_any
+++ /dev/null
@@ -1 +0,0 @@
-ANY \ No newline at end of file
diff --git a/test/afl_dictionary/string_brackets b/test/afl_dictionary/string_brackets
deleted file mode 100644
index 0637a08..0000000
--- a/test/afl_dictionary/string_brackets
+++ /dev/null
@@ -1 +0,0 @@
-[] \ No newline at end of file
diff --git a/test/afl_dictionary/string_cdata b/test/afl_dictionary/string_cdata
deleted file mode 100644
index 9d6d94e..0000000
--- a/test/afl_dictionary/string_cdata
+++ /dev/null
@@ -1 +0,0 @@
-CDATA \ No newline at end of file
diff --git a/test/afl_dictionary/string_dashes b/test/afl_dictionary/string_dashes
deleted file mode 100644
index 7489acc..0000000
--- a/test/afl_dictionary/string_dashes
+++ /dev/null
@@ -1 +0,0 @@
--- \ No newline at end of file
diff --git a/test/afl_dictionary/string_empty_dblquotes b/test/afl_dictionary/string_empty_dblquotes
deleted file mode 100644
index 3cc762b..0000000
--- a/test/afl_dictionary/string_empty_dblquotes
+++ /dev/null
@@ -1 +0,0 @@
-"" \ No newline at end of file
diff --git a/test/afl_dictionary/string_empty_quotes b/test/afl_dictionary/string_empty_quotes
deleted file mode 100644
index 9423090..0000000
--- a/test/afl_dictionary/string_empty_quotes
+++ /dev/null
@@ -1 +0,0 @@
-'' \ No newline at end of file
diff --git a/test/afl_dictionary/string_idrefs b/test/afl_dictionary/string_idrefs
deleted file mode 100644
index dd37f9c..0000000
--- a/test/afl_dictionary/string_idrefs
+++ /dev/null
@@ -1 +0,0 @@
-IDREFS \ No newline at end of file
diff --git a/test/afl_dictionary/string_parentheses b/test/afl_dictionary/string_parentheses
deleted file mode 100644
index dd626a0..0000000
--- a/test/afl_dictionary/string_parentheses
+++ /dev/null
@@ -1 +0,0 @@
-() \ No newline at end of file
diff --git a/test/afl_dictionary/string_pcdata b/test/afl_dictionary/string_pcdata
deleted file mode 100644
index d2dd7f7..0000000
--- a/test/afl_dictionary/string_pcdata
+++ /dev/null
@@ -1 +0,0 @@
-#PCDATA \ No newline at end of file
diff --git a/test/afl_dictionary/tag_cdata b/test/afl_dictionary/tag_cdata
deleted file mode 100644
index fac6255..0000000
--- a/test/afl_dictionary/tag_cdata
+++ /dev/null
@@ -1 +0,0 @@
-<![CDATA[ \ No newline at end of file
diff --git a/test/afl_dictionary/tag_close b/test/afl_dictionary/tag_close
deleted file mode 100644
index e8a17f4..0000000
--- a/test/afl_dictionary/tag_close
+++ /dev/null
@@ -1 +0,0 @@
-</a> \ No newline at end of file
diff --git a/test/afl_dictionary/tag_doctype b/test/afl_dictionary/tag_doctype
deleted file mode 100644
index b771752..0000000
--- a/test/afl_dictionary/tag_doctype
+++ /dev/null
@@ -1 +0,0 @@
-<!DOCTYPE \ No newline at end of file
diff --git a/test/afl_dictionary/tag_element b/test/afl_dictionary/tag_element
deleted file mode 100644
index 04ad1f5..0000000
--- a/test/afl_dictionary/tag_element
+++ /dev/null
@@ -1 +0,0 @@
-<!ELEMENT \ No newline at end of file
diff --git a/test/afl_dictionary/tag_entity b/test/afl_dictionary/tag_entity
deleted file mode 100644
index ee9f1f3..0000000
--- a/test/afl_dictionary/tag_entity
+++ /dev/null
@@ -1 +0,0 @@
-<!ENTITY \ No newline at end of file
diff --git a/test/afl_dictionary/tag_notation b/test/afl_dictionary/tag_notation
deleted file mode 100644
index 749f920..0000000
--- a/test/afl_dictionary/tag_notation
+++ /dev/null
@@ -1 +0,0 @@
-<!NOTATION \ No newline at end of file
diff --git a/test/afl_dictionary/tag_open b/test/afl_dictionary/tag_open
deleted file mode 100644
index 6411313..0000000
--- a/test/afl_dictionary/tag_open
+++ /dev/null
@@ -1 +0,0 @@
-<a> \ No newline at end of file
diff --git a/test/afl_dictionary/tag_open_close b/test/afl_dictionary/tag_open_close
deleted file mode 100644
index 4a12235..0000000
--- a/test/afl_dictionary/tag_open_close
+++ /dev/null
@@ -1 +0,0 @@
-<a /> \ No newline at end of file
diff --git a/test/afl_dictionary/tag_open_exclamation b/test/afl_dictionary/tag_open_exclamation
deleted file mode 100644
index 58adc03..0000000
--- a/test/afl_dictionary/tag_open_exclamation
+++ /dev/null
@@ -1 +0,0 @@
-<! \ No newline at end of file
diff --git a/test/afl_dictionary/tag_open_q b/test/afl_dictionary/tag_open_q
deleted file mode 100644
index 2b4439c..0000000
--- a/test/afl_dictionary/tag_open_q
+++ /dev/null
@@ -1 +0,0 @@
-<? \ No newline at end of file
diff --git a/test/afl_dictionary/tag_sq2_close b/test/afl_dictionary/tag_sq2_close
deleted file mode 100644
index facf683..0000000
--- a/test/afl_dictionary/tag_sq2_close
+++ /dev/null
@@ -1 +0,0 @@
-]]> \ No newline at end of file
diff --git a/test/afl_dictionary/tag_xml_q b/test/afl_dictionary/tag_xml_q
deleted file mode 100644
index be32990..0000000
--- a/test/afl_dictionary/tag_xml_q
+++ /dev/null
@@ -1 +0,0 @@
-<?xml?> \ No newline at end of file
diff --git a/test/afl_dictionary/underscore b/test/afl_dictionary/underscore
deleted file mode 100644
index c9cdc63..0000000
--- a/test/afl_dictionary/underscore
+++ /dev/null
@@ -1 +0,0 @@
-_ \ No newline at end of file
diff --git a/test/cmark-fuzz.c b/test/cmark-fuzz.c
new file mode 100644
index 0000000..f09db52
--- /dev/null
+++ b/test/cmark-fuzz.c
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include "cmark.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int options = 0;
+ if (size > sizeof(options)) {
+ /* First 4 bytes of input are treated as options */
+ int options = *(const int *)data;
+
+ /* Mask off valid option bits */
+ options = options & (CMARK_OPT_SOURCEPOS | CMARK_OPT_HARDBREAKS | CMARK_OPT_SAFE | CMARK_OPT_NOBREAKS | CMARK_OPT_NORMALIZE | CMARK_OPT_VALIDATE_UTF8 | CMARK_OPT_SMART);
+
+ /* Remainder of input is the markdown */
+ const char *markdown = (const char *)(data + sizeof(options));
+ const size_t markdown_size = size - sizeof(options);
+ cmark_node *doc = cmark_parse_document(markdown, markdown_size, options);
+
+ free(cmark_render_commonmark(doc, options, 80));
+ free(cmark_render_html(doc, options));
+ free(cmark_render_latex(doc, options, 80));
+ free(cmark_render_man(doc, options, 80));
+ free(cmark_render_xml(doc, options));
+
+ cmark_node_free(doc);
+ }
+ return 0;
+}
diff --git a/test/fuzzing_dictionary b/test/fuzzing_dictionary
new file mode 100644
index 0000000..b06783c
--- /dev/null
+++ b/test/fuzzing_dictionary
@@ -0,0 +1,49 @@
+asterisk="*"
+attr_generic=" a=\"1\""
+attr_href=" href=\"1\""
+attr_xml_lang=" xml:lang=\"1\""
+attr_xmlns=" xmlns=\"1\""
+backslash="\\"
+backtick="`"
+colon=":"
+dashes="---"
+double_quote="\""
+entity_builtin="&lt;"
+entity_decimal="&#1;"
+entity_external="&a;"
+entity_hex="&#x1;"
+equals="==="
+exclamation="!"
+greater_than=">"
+hash="#"
+hyphen="-"
+indent=" "
+left_bracket="["
+left_paren="("
+less_than="<"
+plus="+"
+right_bracket="]"
+right_paren=")"
+single_quote="'"
+string_any="ANY"
+string_brackets="[]"
+string_cdata="CDATA"
+string_dashes="--"
+string_empty_dblquotes="\"\""
+string_empty_quotes="''"
+string_idrefs="IDREFS"
+string_parentheses="()"
+string_pcdata="#PCDATA"
+tag_cdata="<![CDATA["
+tag_close="</a>"
+tag_doctype="<!DOCTYPE"
+tag_element="<!ELEMENT"
+tag_entity="<!ENTITY"
+tag_notation="<!NOTATION"
+tag_open="<a>"
+tag_open_close="<a />"
+tag_open_exclamation="<!"
+tag_open_q="<?"
+tag_sq2_close="]]>"
+tag_xml_q="<?xml?>"
+underscore="_"
diff --git a/test/run-cmark-fuzz b/test/run-cmark-fuzz
new file mode 100755
index 0000000..75100b8
--- /dev/null
+++ b/test/run-cmark-fuzz
@@ -0,0 +1,4 @@
+#!/bin/bash -eu
+CMARK_FUZZ="$1"
+shift
+ASAN_OPTIONS="quarantine_size_mb=10:detect_leaks=1" "${CMARK_FUZZ}" -max_len=256 -timeout=1 -dict=test/fuzzing_dictionary "$@"