diff --git a/.gitignore b/.gitignore index dd12a74b..417b9e49 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ cmake-build-* benchmark-dir .conan/test_package/build bazel-* +build-fuzzers diff --git a/CMakeLists.txt b/CMakeLists.txt index 009fec94..bbe21d29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ include(CMakeDependentOption) cmake_dependent_option(CATCH_BUILD_TESTING "Build the SelfTest project" ON "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_BUILD_EXAMPLES "Build code examples" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF "CATCH_DEVELOPMENT_BUILD" OFF) +cmake_dependent_option(CATCH_BUILD_FUZZERS "Build fuzzers" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF) @@ -73,6 +74,9 @@ if(CATCH_BUILD_EXTRA_TESTS) add_subdirectory(tests/ExtraTests) endif() +if(CATCH_BUILD_FUZZERS) + add_subdirectory(fuzzing) +endif() if (CATCH_DEVELOPMENT_BUILD) add_warnings_to_targets("${CATCH_WARNING_TARGETS}") diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 00000000..7c5ac4dd --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,17 @@ +# License: Boost 1.0 +# By Paul Dreik 2020 + +# add a library that brings in the main() function from libfuzzer +# and has all the dependencies, so the individual fuzzers can be +# added one line each. +add_library(fuzzhelper NullOStream.h NullOStream.cpp) +target_link_libraries(fuzzhelper PUBLIC Catch2::Catch2) + +# This should be possible to set from the outside to be oss-fuzz compatible, +# fix later. For now, target libFuzzer only. +target_link_options(fuzzhelper PUBLIC "-fsanitize=fuzzer") + +foreach(fuzzer TestSpecParser XmlWriter) +add_executable(fuzz_${fuzzer} fuzz_${fuzzer}.cpp) +target_link_libraries(fuzz_${fuzzer} PRIVATE fuzzhelper) +endforeach() diff --git a/fuzzing/NullOStream.cpp b/fuzzing/NullOStream.cpp new file mode 100644 index 00000000..53e0893d --- /dev/null +++ b/fuzzing/NullOStream.cpp @@ -0,0 +1,10 @@ +#include "NullOStream.h" + +void NullOStream::avoidOutOfLineVirtualCompilerWarning() +{ +} + +int NullStreambuf::overflow(int c){ + setp(dummyBuffer, dummyBuffer + sizeof(dummyBuffer)); + return (c == traits_type::eof()) ? '\0' : c; +} diff --git a/fuzzing/NullOStream.h b/fuzzing/NullOStream.h new file mode 100644 index 00000000..fc13777b --- /dev/null +++ b/fuzzing/NullOStream.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +// from https://stackoverflow.com/a/8244052 +class NullStreambuf : public std::streambuf { + char dummyBuffer[64]; + +protected: + virtual int overflow(int c) override final; +}; + +class NullOStream final : private NullStreambuf, public std::ostream { +public: + NullOStream() : std::ostream(this) {} + NullStreambuf *rdbuf() { return this; } + virtual void avoidOutOfLineVirtualCompilerWarning(); +}; + + diff --git a/fuzzing/build_fuzzers.sh b/fuzzing/build_fuzzers.sh new file mode 100755 index 00000000..9788c68c --- /dev/null +++ b/fuzzing/build_fuzzers.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Builds the fuzzers +# +# By Paul Dreik 20200923 +set -exu + +CATCHROOT=$(readlink -f $(dirname $0)/..) + + +BUILDDIR=$CATCHROOT/build-fuzzers +mkdir -p $BUILDDIR +cd $BUILDDIR + +if which /usr/lib/ccache/clang++ >/dev/null 2>&1 ; then + CXX=/usr/lib/ccache/clang++ +else + CXX=clang++ +fi + +cmake $CATCHROOT \ + -DCMAKE_CXX_COMPILER=$CXX \ + -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link,address,undefined -O3 -g" \ + -DCATCH_DEVELOPMENT_BUILD=On \ + -DCATCH_BUILD_EXAMPLES=Off \ + -DCATCH_BUILD_EXTRA_TESTS=Off \ + -DCATCH_BUILD_TESTING=Off \ + -DBUILD_TESTING=Off \ + -DCATCH_ENABLE_WERROR=Off \ + -DCATCH_BUILD_FUZZERS=On + +cmake --build . -j $(nproc) + diff --git a/fuzzing/fuzz_TestSpecParser.cpp b/fuzzing/fuzz_TestSpecParser.cpp new file mode 100644 index 00000000..af4de406 --- /dev/null +++ b/fuzzing/fuzz_TestSpecParser.cpp @@ -0,0 +1,16 @@ +//License: Boost 1.0 +//By Paul Dreik 2020 + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + + Catch::TagAliasRegistry tar; + Catch::TestSpecParser tsp(tar); + + std::string buf(Data,Data+Size); + tsp.parse(buf); + + return 0; +} diff --git a/fuzzing/fuzz_XmlWriter.cpp b/fuzzing/fuzz_XmlWriter.cpp new file mode 100644 index 00000000..f8e5a0d9 --- /dev/null +++ b/fuzzing/fuzz_XmlWriter.cpp @@ -0,0 +1,16 @@ +//License: Boost 1.0 +//By Paul Dreik 2020 + +#include + +#include "NullOStream.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + + std::string buf(Data,Data+Size); + NullOStream nul; + Catch::XmlEncode encode(buf); + encode.encodeTo(nul); + return 0; +} +