Add the CMake integration for the fuzzing tool

This commit is contained in:
Florian Albrechtskirchinger 2022-08-01 14:48:10 +02:00
parent 3162a30858
commit 5fb19f9856
No known key found for this signature in database
GPG Key ID: 19618CE9B2D4BE6D
3 changed files with 115 additions and 1 deletions

View File

@ -48,6 +48,8 @@ option(JSON_Install "Install CMake targets during install
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON)
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
option(JSON_BuildFuzzers "Build fuzz testing binaries. Requires JSON_BuildTests=ON." OFF)
if (JSON_CI)
include(ci)
endif ()
@ -145,7 +147,7 @@ CONFIGURE_FILE(
##
## TESTS
## create and configure the unit test target
## create and configure the unit test target; build fuzzers, if enabled
##
if (JSON_BuildTests)
include(CTest)

View File

@ -172,3 +172,11 @@ add_subdirectory(cmake_add_subdirectory)
add_subdirectory(cmake_fetch_content)
add_subdirectory(cmake_fetch_content2)
add_subdirectory(cmake_target_include_directories)
#############################################################################
# fuzz testing
#############################################################################
if(JSON_BuildFuzzers)
add_subdirectory(fuzz)
endif()

104
tests/fuzz/CMakeLists.txt Normal file
View File

@ -0,0 +1,104 @@
set(JSON_FUZZ_ENGINE "afl++" CACHE STRING "The engine to use for fuzz testing.")
set(JSON_FUZZ_TARGETS "json;bjdata;bson;cbor;msgpack;ubjson" CACHE STRING "List of targets/formats to fuzz test.")
set(JSON_FUZZ_SANITIZERS "asan+cfisan+lsan+ubsan;msan" CACHE STRING "List of sanitizers/combinations of sanitizers to build fuzzers for.")
set(JSON_FUZZ_CORPUS_MAX_SIZE "5k" CACHE STRING "Maximum file size for corpus data.")
option(JSON_FUZZ_MINIMIZE_CORPUS "Minimize the corpa generated from test data." ON)
set(JSON_FUZZ_TEMP_DIR "" CACHE PATH "Path to temporary directory. Should be on a tmpfs or equivalent (AFL++).")
set(JSON_FUZZ_NUM_JOBS 8 CACHE STRING "Number of parallel fuzzing jobs.")
set(JSON_FUZZ_AFL_DIR "" CACHE PATH "Path to AFL++.")
set(JSON_FUZZ_AFL_INSTRUMENTATIONS "laf-intel;complog" CACHE STRING "List of AFL++ instrumentations to build fuzzers for.")
option(JSON_FUZZ_AFL_EXIT_WHEN_DONE "Exit fuzzer when no new paths have been discovered for a while." ON)
set(JSON_FUZZ_MAX_TIME "" ON)
include(fuzz)
# find_program() requires permission to execute but not to read
cmake_policy(SET CMP0109 NEW)
#############################################################################
# validate settings
#############################################################################
# check fuzz engine
string(TOLOWER "${JSON_FUZZ_ENGINE}" fuzz_engine)
if(NOT "${fuzz_engine}" STREQUAL "afl++")
message(FATAL_ERROR "Unsupoorted fuzz engine: ${fuzz_engine}")
endif()
set(JSON_FUZZ_ENGINE "${fuzz_engine}" CACHE STRING "" FORCE)
if(${JSON_FUZZ_ENGINE} STREQUAL afl++)
# find compiler
find_program (JSON_FUZZ_CXX_COMPILER
NAMES afl-clang-lto++ afl-clang-fast++
DOC "AFL++ C++ compiler" REQUIRED)
find_program (JSON_FUZZ_AFL_FUZZ
NAMES afl-fuzz
DOC "AFL++ fuzzer runner" REQUIRED)
if(JSON_FUZZ_MINIMIZE_CORPUS)
find_program (JSON_FUZZ_AFL_CMIN
NAMES afl-cmin
DOC "AFL++ corpus minimizer" REQUIRED)
endif()
elseif(${JSON_FUZZ_ENGINE} STREQUAL libfuzzer)
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang)
set(JSON_FUZZ_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
endif()
find_program (JSON_FUZZ_CXX_COMPILER
NAMES clang++
DOC "Clang C++ compiler" REQUIRED)
endif()
# TODO does libFuzzer hammer the disk as much as AFL++?
if(${JSON_FUZZ_ENGINE} STREQUAL afl++)
if(NOT JSON_FUZZ_TEMP_DIR)
# try to default AFL++ temp. directory to XDG_RUNTIME_DIR on Linux
if(UNIX AND NOT APPLE AND DEFINED ENV{XDG_RUNTIME_DIR})
find_program(mount_program mount)
if(mount_program)
execute_process(COMMAND ${mount_program}
OUTPUT_VARIABLE mount_output
ERROR_QUIET)
string(REGEX MATCH "[^ ]+ on $ENV{XDG_RUNTIME_DIR}(/[^ ]*)? type tmpfs" mount_match "${mount_output}")
if(mount_match)
string(RANDOM suffix)
set(temp_dir "$ENV{XDG_RUNTIME_DIR}/json_fuzz_tmp.${suffix}")
set(JSON_FUZZ_TEMP_DIR "${temp_dir}" CACHE PATH "" FORCE)
endif()
endif()
endif()
endif()
if(NOT JSON_FUZZ_TEMP_DIR)
message(WARNING "JSON_FUZZ_TEMP_DIR should point to a directory on an in-memory file system.")
string(RANDOM suffix)
set(temp_dir "$ENV{CMAKE_CURRENT_BINARY_DIR}/json_fuzz_tmp.${suffix}")
set(JSON_FUZZ_TEMP_DIR "${temp_dir}" CACHE PATH "" FORCE)
endif()
message(STATUS "Temporary directory for fuzzing: ${JSON_FUZZ_TEMP_DIR}")
endif()
#############################################################################
# set up fuzzing
#############################################################################
foreach(target ${JSON_FUZZ_TARGETS})
json_fuzz_add_fuzzers(${target}
SOURCES src/fuzzer-parse_${target}.cpp
ENGINE ${JSON_FUZZ_ENGINE}
SANITIZERS ${JSON_FUZZ_SANITIZERS}
INSTRUMENTATIONS ${JSON_FUZZ_AFL_INSTRUMENTATIONS})
json_fuzz_add_corpus(${target} GLOB "**/*.${target}"
MAX_SIZE ${JSON_FUZZ_CORPUS_MAX_SIZE})
if(JSON_FUZZ_MINIMIZE_CORPUS)
json_fuzz_minimize_corpus(${target}
ENGINE ${JSON_FUZZ_ENGINE})
endif()
json_fuzz_add_fuzz_run_target(${target}
TEMP_DIR "${JSON_FUZZ_TEMP_DIR}")
endforeach()