#!/usr/bin/env bash # shellcheck disable=SC2086 set -e if [[ $(uname -s) != Linux ]]; then printf 'Fuzzing is only supported on Linux\n' >&2 exit 1 fi CC=${CC:-clang} CXX=${CXX:-clang++} default_fuzz_flags=-fsanitize=fuzzer,address,undefined export CFLAGS="$default_fuzz_flags $CFLAGS" export CXXFLAGS="$default_fuzz_flags $CXXFLAGS" make CC="$CC" CXX="$CXX" libtree-sitter.a if [[ -z $* ]]; then mapfile -t languages < <(ls test/fixtures/grammars) else languages=("$@") fi mkdir -p test/fuzz/out for lang in "${languages[@]}"; do # skip typescript & php if [[ $lang == typescript || $lang == php ]]; then continue fi printf 'Building %s fuzzer...\n' "$lang" lang_dir="test/fixtures/grammars/$lang" lang_grammar="${lang_dir}/src/grammar.json" # The following assumes each language is implemented as src/parser.c plus an # optional scanner in src/scanner.c objects=() lang_scanner="${lang_dir}/src/scanner" if [[ -f "${lang_scanner}.c" ]]; then $CC $CFLAGS -std=c11 -g -O1 -I "${lang_dir}/src" -c "${lang_scanner}.c" -o "${lang_scanner}.o" objects+=("${lang_scanner}.o") fi # Compiling with -O0 speeds up the build dramatically $CC $CFLAGS -g -O0 -I "${lang_dir}/src" "${lang_dir}/src/parser.c" -c -o "${lang_dir}/src/parser.o" objects+=("${lang_dir}/src/parser.o") highlights_filename="${lang_dir}/queries/highlights.scm" if [[ -f "${highlights_filename}" ]]; then ts_lang_query_filename="${lang}.scm" cp "${highlights_filename}" "test/fuzz/out/${ts_lang_query_filename}" else ts_lang_query_filename="" fi ts_lang="tree_sitter_$(jq -r .name "$lang_grammar")" $CXX $CXXFLAGS -std=c++11 -Ilib/include \ -D TS_LANG="$ts_lang" \ -D TS_LANG_QUERY_FILENAME="\"${ts_lang_query_filename}\"" \ test/fuzz/fuzzer.cc \ "${objects[@]}" \ libtree-sitter.a \ -o "test/fuzz/out/${lang}_fuzzer" jq ' [ .. | if .type? == "STRING" or (.type? == "ALIAS" and .named? == false) then .value else empty end | select(test("\\S") and length == utf8bytelength) ] | unique | .[] ' "$lang_grammar" | sort > "test/fuzz/out/${lang}.dict" done