From a23b7a198ba739dd813897901855c98441e6f29b Mon Sep 17 00:00:00 2001 From: Paul Dreik Date: Fri, 14 Jun 2019 18:56:40 +0200 Subject: [PATCH] refactor --- test/fuzzing/CMakeLists.txt | 4 ++-- test/fuzzing/chrono_duration.cpp | 19 +++++----------- test/fuzzing/fuzzer_common.h | 37 ++++++++++++++++++++++++++++++++ test/fuzzing/named_arg.cpp | 7 +++--- test/fuzzing/one_arg.cpp | 12 +++++------ test/fuzzing/sprintf.cpp | 8 +++---- test/fuzzing/two_args.cpp | 9 ++++---- 7 files changed, 60 insertions(+), 36 deletions(-) create mode 100644 test/fuzzing/fuzzer_common.h diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt index e34f14f15128..df5c23f85bbd 100644 --- a/test/fuzzing/CMakeLists.txt +++ b/test/fuzzing/CMakeLists.txt @@ -12,7 +12,7 @@ set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets") #find all fuzzers. set(SOURCES -chrono_duration.cpp # this triggers integer overflows I yet not know how to fix +chrono_duration.cpp named_arg.cpp one_arg.cpp sprintf.cpp @@ -26,7 +26,7 @@ endif() macro(implement_fuzzer sourcefile) get_filename_component(basename ${sourcefile} NAME_WE) set(name fuzzer_${basename}) - add_executable(${name} ${sourcefile}) + add_executable(${name} ${sourcefile} fuzzer_common.h) target_link_libraries(${name} PRIVATE fmt) if(FMT_FUZZ_LDFLAGS) target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS}) diff --git a/test/fuzzing/chrono_duration.cpp b/test/fuzzing/chrono_duration.cpp index 361beb3aabf4..96cf1d72c299 100644 --- a/test/fuzzing/chrono_duration.cpp +++ b/test/fuzzing/chrono_duration.cpp @@ -8,17 +8,13 @@ #include #include #include +#include "fuzzer_common.h" template void invoke_inner(fmt::string_view formatstring, const Item item) { const std::chrono::duration value(item); try { - // Don't switch these two dynamically, - // there is already a large combinatoric explosion - // of type and ratio, causing afl to suffer and the corpus - // getting enormous. Occasionally, flip this switch and - // try manually. -#if 0 +#if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(formatstring, value); #else fmt::memory_buffer buf; @@ -31,12 +27,8 @@ void invoke_inner(fmt::string_view formatstring, const Item item) { // Item is the underlying type for duration (int, long etc) template void invoke_outer(const uint8_t* Data, std::size_t Size, const int scaling) { - // always use a fixed location of the data, so different cases will - // cooperate better. the same bit pattern, interpreted as another type, - // is likely interesting. - // won't work on travis. - //constexpr auto Nfixed = std::max(sizeof(long double), sizeof(std::intmax_t)); - constexpr auto Nfixed=16; + // always use a fixed location of the data + using fmt_fuzzer::Nfixed; constexpr auto N = sizeof(Item); static_assert(N <= Nfixed, "fixed size is too small"); @@ -44,8 +36,7 @@ void invoke_outer(const uint8_t* Data, std::size_t Size, const int scaling) { return; } - // travis doesn't handle this -#if 0 +#if __cplusplus >= 201402L static_assert(std::is_trivially_copyable::value, "Item must be blittable"); #endif diff --git a/test/fuzzing/fuzzer_common.h b/test/fuzzing/fuzzer_common.h new file mode 100644 index 000000000000..ff2687e432c9 --- /dev/null +++ b/test/fuzzing/fuzzer_common.h @@ -0,0 +1,37 @@ +#ifndef FUZZER_COMMON_H +#define FUZZER_COMMON_H +// Copyright (c) 2019, Paul Dreik +// License: see LICENSE.rst in the fmt root directory + +// one can format to either a string, or a buf. buf is faster, +// but one may be interested in formatting to a string instead to +// verify it works as intended. to avoid a combinatoric explosion, +// select this at compile time instead of dynamically from the fuzz data +#define FMT_FUZZ_FORMAT_TO_STRING 1 + +// if fmt is given a buffer that is separately allocated, +// chances that address sanitizer detects out of bound reads is +// much higher. However, it slows down the fuzzing. +#define FMT_FUZZ_SEPARATE_ALLOCATION 1 + + + +// To let the the fuzzer mutation be efficient at cross pollinating +// between different types, use a fixed size format. +// The same bit pattern, interpreted as another type, +// is likely interesting. +// For this, we must know the size of the largest possible type in use. +// There are some problems on old compilers, hence the C++ version check +#if __cplusplus >= 201402L +# include +# include +namespace fmt_fuzzer { + constexpr auto Nfixed = std::max(sizeof(long double), sizeof(std::intmax_t)); +} +#else +namespace fmt_fuzzer { + constexpr auto Nfixed=16; +} +#endif + +#endif // FUZZER_COMMON_H diff --git a/test/fuzzing/named_arg.cpp b/test/fuzzing/named_arg.cpp index beb4ad2e76d0..e966413b8fd6 100644 --- a/test/fuzzing/named_arg.cpp +++ b/test/fuzzing/named_arg.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "fuzzer_common.h" template void invoke_fmt(const uint8_t* Data, std::size_t Size, int argsize) { @@ -30,8 +31,7 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size, int argsize) { // allocating buffers separately is slower, but increases chances // of detecting memory errors -#define SEPARATE_ALLOCATION 1 -#if SEPARATE_ALLOCATION +#if FMT_FUZZ_SEPARATE_ALLOCATION std::vector argnamebuffer(argsize); std::memcpy(argnamebuffer.data(), Data, argsize); auto argname = fmt::string_view(argnamebuffer.data(), argsize); @@ -41,7 +41,7 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size, int argsize) { Data += argsize; Size -= argsize; -#if SEPARATE_ALLOCATION +#if FMT_FUZZ_SEPARATE_ALLOCATION // allocates as tight as possible, making it easier to catch buffer overruns. std::vector fmtstringbuffer(Size); std::memcpy(fmtstringbuffer.data(), Data, Size); @@ -50,7 +50,6 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size, int argsize) { auto fmtstring = fmt::string_view((const char*)Data, Size); #endif std::string message = fmt::format(fmtstring, fmt::arg(argname, item1)); -#undef SEPARATE_ALLOCATION } // for dynamic dispatching to an explicit instantiation diff --git a/test/fuzzing/one_arg.cpp b/test/fuzzing/one_arg.cpp index c29506d3d412..88f7e7add279 100644 --- a/test/fuzzing/one_arg.cpp +++ b/test/fuzzing/one_arg.cpp @@ -8,6 +8,7 @@ #include #include +#include "fuzzer_common.h" template void invoke_fmt(const uint8_t* Data, std::size_t Size) { @@ -24,8 +25,7 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size) { Data += N; Size -= N; -#define SEPARATE_ALLOCATION 0 -#if SEPARATE_ALLOCATION +#if FMT_FUZZ_SEPARATE_ALLOCATION // allocates as tight as possible, making it easier to catch buffer overruns. std::vector fmtstringbuffer(Size); std::memcpy(fmtstringbuffer.data(), Data, Size); @@ -33,8 +33,8 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size) { #else auto fmtstring = fmt::string_view((const char*)Data, Size); #endif -#define ALLOCATE_RESULT_IN_STRING 0 -#if ALLOCATE_RESULT_IN_STRING + +#if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(fmtstring, item); #else fmt::memory_buffer message; @@ -52,7 +52,7 @@ void invoke_fmt_time(const uint8_t* Data, std::size_t Size) { std::memcpy(&item, Data, N); Data += N; Size -= N; -#if SEPARATE_ALLOCATION +#if FMT_FUZZ_SEPARATE_ALLOCATION // allocates as tight as possible, making it easier to catch buffer overruns. std::vector fmtstringbuffer(Size); std::memcpy(fmtstringbuffer.data(), Data, Size); @@ -62,7 +62,7 @@ void invoke_fmt_time(const uint8_t* Data, std::size_t Size) { #endif auto* b = std::localtime(&item); if (b) { -#if ALLOCATE_RESULT_IN_STRING +#if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(fmtstring, *b); #else fmt::memory_buffer message; diff --git a/test/fuzzing/sprintf.cpp b/test/fuzzing/sprintf.cpp index b1b623b00701..5f4facb963d9 100644 --- a/test/fuzzing/sprintf.cpp +++ b/test/fuzzing/sprintf.cpp @@ -5,10 +5,9 @@ #include #include +#include "fuzzer_common.h" -// won't work on travis. -//constexpr auto Nmax = std::max(sizeof(long double), sizeof(std::intmax_t)); -constexpr auto Nmax=16; +constexpr auto Nmax=fmt_fuzzer::Nfixed; template Item assignFromBuf(const uint8_t* Data, std::size_t Size) { @@ -40,8 +39,7 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size) { auto fmtstring = fmt::string_view((const char*)Data, Size); -#define ALLOCATE_RESULT_IN_STRING 0 -#if ALLOCATE_RESULT_IN_STRING +#if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(fmtstring, item1, item2); #else fmt::memory_buffer message; diff --git a/test/fuzzing/two_args.cpp b/test/fuzzing/two_args.cpp index 81a16d455be6..e5ed66d0a3c5 100644 --- a/test/fuzzing/two_args.cpp +++ b/test/fuzzing/two_args.cpp @@ -5,9 +5,9 @@ #include #include -// won't work on travis. -//constexpr auto Nmax = std::max(sizeof(long double), sizeof(std::intmax_t)); -constexpr auto Nmax=16; +#include "fuzzer_common.h" + +constexpr auto Nmax=fmt_fuzzer::Nfixed; template void invoke_fmt(const uint8_t* Data, std::size_t Size) { @@ -38,8 +38,7 @@ void invoke_fmt(const uint8_t* Data, std::size_t Size) { auto fmtstring = fmt::string_view((const char*)Data, Size); -#define ALLOCATE_RESULT_IN_STRING 0 -#if ALLOCATE_RESULT_IN_STRING +#if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(fmtstring, item1, item2); #else fmt::memory_buffer message;