diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fac2afc..0204cf96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,7 +330,13 @@ endif () # Control fuzzing independent of the unit tests. if (FMT_FUZZ) add_subdirectory(test/fuzzing) - target_compile_definitions(fmt PUBLIC FMT_FUZZ) + + # The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing + # mode and make fuzzing practically possible. It is similar to + # FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to + # avoid interfering with fuzzing of projects that use {fmt}. + # See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode. + target_compile_definitions(fmt PRIVATE FMT_FUZZ) endif () set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore) diff --git a/test/compile-test.cc b/test/compile-test.cc index b79b9ea9..c0dda50c 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -5,19 +5,10 @@ // // For the license information refer to format.h. -#include - -#include -#include -#include -#include -#include -#include -#include -#include #include +#include -// Check if fmt/compile.h compiles with windows.h included before it. +// Check that fmt/compile.h compiles with windows.h included before it. #ifdef _WIN32 # include #endif @@ -25,16 +16,8 @@ #include "fmt/compile.h" #include "gmock.h" #include "gtest-extra.h" -#include "mock-allocator.h" #include "util.h" -#undef ERROR -#undef min -#undef max - -using testing::Return; -using testing::StrictMock; - // compiletime_prepared_parts_type_provider is useful only with relaxed // constexpr. #if FMT_USE_CONSTEXPR diff --git a/test/format-dyn-args-test.cc b/test/format-dyn-args-test.cc deleted file mode 100644 index acc5ef78..00000000 --- a/test/format-dyn-args-test.cc +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2020 Vladimir Solontsov -// SPDX-License-Identifier: MIT Licence - -#include - -#include "gtest-extra.h" diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt index 5f589d7a..352ddcca 100644 --- a/test/fuzzing/CMakeLists.txt +++ b/test/fuzzing/CMakeLists.txt @@ -1,37 +1,28 @@ # Copyright (c) 2019, Paul Dreik # License: see LICENSE.rst in the fmt root directory -# settings this links in a main. useful for reproducing, -# kcov, gdb, afl, valgrind. -# (note that libFuzzer can also reproduce, just pass it the files) -option(FMT_FUZZ_LINKMAIN "enables the reproduce mode, instead of libFuzzer" On) +# Link in the main function. Useful for reproducing, kcov, gdb, afl, valgrind. +# (Note that libFuzzer can also reproduce, just pass it the files.) +option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On) # For oss-fuzz - insert $LIB_FUZZING_ENGINE into the link flags, but only for -# the fuzz targets, otherwise the cmake configuration step fails. +# the fuzz targets, otherwise the CMake configuration step fails. set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets") -# Find all fuzzers. -set(SOURCES - chrono_duration.cpp - named_arg.cpp - one_arg.cpp - two_args.cpp -) - -macro(implement_fuzzer sourcefile) - get_filename_component(basename ${sourcefile} NAME_WE) +function(add_fuzzer source) + get_filename_component(basename ${source} NAME_WE) set(name fuzzer_${basename}) - add_executable(${name} ${sourcefile} fuzzer_common.h) + add_executable(${name} ${source} fuzzer-common.h) if (FMT_FUZZ_LINKMAIN) - target_sources(${name} PRIVATE main.cpp) + target_sources(${name} PRIVATE main.cc) endif () target_link_libraries(${name} PRIVATE fmt) -if (FMT_FUZZ_LDFLAGS) - target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS}) -endif () + if (FMT_FUZZ_LDFLAGS) + target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS}) + endif () target_compile_features(${name} PRIVATE cxx_generic_lambdas) -endmacro () +endfunction() -foreach (X IN ITEMS ${SOURCES}) - implement_fuzzer(${X}) +foreach (source chrono-duration.cc named-arg.cc one-arg.cc two-args.cc) + add_fuzzer(${source}) endforeach () diff --git a/test/fuzzing/README.md b/test/fuzzing/README.md index 8f7a4536..bb3d0e04 100644 --- a/test/fuzzing/README.md +++ b/test/fuzzing/README.md @@ -1,27 +1,4 @@ -# FMT Fuzzer - -Fuzzing has revealed [several bugs](https://github.com/fmtlib/fmt/issues?&q=is%3Aissue+fuzz) -in fmt. It is a part of the continous fuzzing at -[oss-fuzz](https://github.com/google/oss-fuzz). - -The source code is modified to make the fuzzing possible without locking up on -resource exhaustion: -```cpp -#ifdef FMT_FUZZ -if(spec.precision>100000) { - throw std::runtime_error("fuzz mode - avoiding large precision"); -} -#endif -``` -This macro `FMT_FUZZ` is enabled on OSS-Fuzz builds and makes fuzzing -practically possible. It is used in fmt code to prevent resource exhaustion in -fuzzing mode. -The macro `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` is the -defacto standard for making fuzzing practically possible to disable certain -fuzzing-unfriendly features (for example, randomness), see [the libFuzzer -documentation](https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode). - -## Running the fuzzers locally +# Running the fuzzers locally There is a [helper script](build.sh) to build the fuzzers, which has only been tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on @@ -34,7 +11,7 @@ mkdir build cd build export CXX=clang++ export CXXFLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g" -cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" +cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" cmake --build . ``` should work to build the fuzzers for all platforms which clang supports. @@ -44,5 +21,5 @@ Execute a fuzzer with for instance cd build export UBSAN_OPTIONS=halt_on_error=1 mkdir out_chrono -bin/fuzzer_chrono_duration out_chrono +bin/fuzzer_chrono_duration out_chrono ``` diff --git a/test/fuzzing/chrono_duration.cpp b/test/fuzzing/chrono-duration.cc similarity index 95% rename from test/fuzzing/chrono_duration.cpp rename to test/fuzzing/chrono-duration.cc index 557d7034..e8e51934 100644 --- a/test/fuzzing/chrono_duration.cpp +++ b/test/fuzzing/chrono-duration.cc @@ -4,11 +4,11 @@ #include #include -#include "fuzzer_common.h" +#include "fuzzer-common.h" template -void invoke_inner(fmt::string_view format_str, const Item item) { - const std::chrono::duration value(item); +void invoke_inner(fmt::string_view format_str, Item item) { + auto value = std::chrono::duration(item); try { #if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(format_str, value); diff --git a/test/fuzzing/fuzzer_common.h b/test/fuzzing/fuzzer-common.h similarity index 100% rename from test/fuzzing/fuzzer_common.h rename to test/fuzzing/fuzzer-common.h diff --git a/test/fuzzing/main.cpp b/test/fuzzing/main.cc similarity index 95% rename from test/fuzzing/main.cpp rename to test/fuzzing/main.cc index 5360bc62..7fd7cc70 100644 --- a/test/fuzzing/main.cpp +++ b/test/fuzzing/main.cc @@ -2,7 +2,7 @@ #include #include -#include "fuzzer_common.h" +#include "fuzzer-common.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); diff --git a/test/fuzzing/named_arg.cpp b/test/fuzzing/named-arg.cc similarity index 98% rename from test/fuzzing/named_arg.cpp rename to test/fuzzing/named-arg.cc index 3b199d6d..9db51555 100644 --- a/test/fuzzing/named_arg.cpp +++ b/test/fuzzing/named-arg.cc @@ -6,7 +6,7 @@ #include #include -#include "fuzzer_common.h" +#include "fuzzer-common.h" template void invoke_fmt(const uint8_t* data, size_t size, unsigned int argsize) { diff --git a/test/fuzzing/one_arg.cpp b/test/fuzzing/one-arg.cc similarity index 97% rename from test/fuzzing/one_arg.cpp rename to test/fuzzing/one-arg.cc index 7d7d5ad3..170d3b0a 100644 --- a/test/fuzzing/one_arg.cpp +++ b/test/fuzzing/one-arg.cc @@ -7,7 +7,7 @@ #include #include -#include "fuzzer_common.h" +#include "fuzzer-common.h" using fmt_fuzzer::nfixed; @@ -15,9 +15,7 @@ template void invoke_fmt(const uint8_t* data, size_t size) { constexpr auto N = sizeof(Item); static_assert(N <= nfixed, "Nfixed is too small"); - if (size <= nfixed) { - return; - } + if (size <= nfixed) return; const Item item = fmt_fuzzer::assignFromBuf(data); data += nfixed; size -= nfixed; diff --git a/test/fuzzing/two_args.cpp b/test/fuzzing/two-args.cc similarity index 96% rename from test/fuzzing/two_args.cpp rename to test/fuzzing/two-args.cc index 983c88c2..bcbd033a 100644 --- a/test/fuzzing/two_args.cpp +++ b/test/fuzzing/two-args.cc @@ -6,12 +6,11 @@ #include #include -#include "fuzzer_common.h" - -constexpr auto nfixed = fmt_fuzzer::nfixed; +#include "fuzzer-common.h" template void invoke_fmt(const uint8_t* data, size_t size) { + using fmt_fuzzer::nfixed; static_assert(sizeof(Item1) <= nfixed, "size1 exceeded"); static_assert(sizeof(Item2) <= nfixed, "size2 exceeded"); if (size <= nfixed + nfixed) return;