Add float fuzzer and cleanup

This commit is contained in:
Victor Zverovich 2020-10-14 07:13:37 -07:00
parent 82c4e2236a
commit 811c8b58c5
6 changed files with 98 additions and 88 deletions

View File

@ -9,6 +9,8 @@ option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On)
# 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") set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets")
# Adds a binary for reproducing, i.e. no fuzzing, just enables replaying data
# through the fuzzers.
function(add_fuzzer source) function(add_fuzzer source)
get_filename_component(basename ${source} NAME_WE) get_filename_component(basename ${source} NAME_WE)
set(name ${basename}-fuzzer) set(name ${basename}-fuzzer)
@ -23,6 +25,6 @@ function(add_fuzzer source)
target_compile_features(${name} PRIVATE cxx_generic_lambdas) target_compile_features(${name} PRIVATE cxx_generic_lambdas)
endfunction() endfunction()
foreach (source chrono-duration.cc named-arg.cc one-arg.cc two-args.cc) foreach (source chrono-duration.cc float.cc named-arg.cc one-arg.cc two-args.cc)
add_fuzzer(${source}) add_fuzzer(${source})
endforeach () endforeach ()

View File

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Creates fuzzer builds of various kinds # Creates fuzzer builds of various kinds
# - reproduce mode (no fuzzing, just enables replaying data through the fuzzers)
# - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works) # - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works)
# - libFuzzer build (you will need clang) # - libFuzzer build (you will need clang)
# - afl build (you will need afl) # - afl build (you will need afl)
@ -23,15 +22,6 @@ here=$(pwd)
CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g" CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17" CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17"
# Builds the fuzzers as one would do if using afl or just making
# binaries for reproducing.
builddir=$here/build-fuzzers-reproduce
mkdir -p $builddir
cd $builddir
CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL" cmake \
$CMAKEFLAGSALL
cmake --build $builddir
# For performance analysis of the fuzzers. # For performance analysis of the fuzzers.
builddir=$here/build-fuzzers-perfanalysis builddir=$here/build-fuzzers-perfanalysis
mkdir -p $builddir mkdir -p $builddir
@ -68,18 +58,6 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir cmake --build $builddir
# Builds fuzzers for local fuzzing with libfuzzer with asan only.
builddir=$here/build-fuzzers-libfuzzer-addr
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
# Builds a fast fuzzer for making coverage fast. # Builds a fast fuzzer for making coverage fast.
builddir=$here/build-fuzzers-fast builddir=$here/build-fuzzers-fast
mkdir -p $builddir mkdir -p $builddir

View File

@ -81,6 +81,7 @@ void invoke_outer(const uint8_t* data, size_t size, int period) {
break; break;
case 15: case 15:
invoke_inner<std::exa>(format_str, rep); invoke_inner<std::exa>(format_str, rep);
break;
} }
} }
@ -129,8 +130,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
case 12: case 12:
invoke_outer<long double>(data, size, period); invoke_outer<long double>(data, size, period);
break; break;
default:
break;
} }
return 0; return 0;
} }

34
test/fuzzing/float.cc Normal file
View File

@ -0,0 +1,34 @@
// A fuzzer for floating-point formatter.
// For the license information refer to format.h.
#include <cstdint>
#include <cstdlib>
#include <stdexcept>
#include <limits>
#include <fmt/format.h>
#include "fuzzer-common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= sizeof(double) || !std::numeric_limits<double>::is_iec559)
return 0;
auto value = assign_from_buf<double>(data);
auto buffer = fmt::memory_buffer();
fmt::format_to(buffer, "{}", value);
// Check a round trip.
if (std::isnan(value)) {
auto nan = std::signbit(value) ? "-nan" : "nan";
if (fmt::string_view(buffer.data(), buffer.size()) != nan)
throw std::runtime_error("round trip failure");
return 0;
}
buffer.push_back('\0');
char* ptr = nullptr;
if (std::strtod(buffer.data(), &ptr) != value)
throw std::runtime_error("round trip failure");
if (ptr != buffer.end())
throw std::runtime_error("unparsed output");
return 0;
}

View File

@ -1,11 +1,10 @@
// Copyright (c) 2019, Paul Dreik // Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h. // For the license information refer to format.h.
#include <fmt/chrono.h>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <fmt/chrono.h>
#include "fuzzer-common.h" #include "fuzzer-common.h"
@ -23,13 +22,16 @@ void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) {
size -= arg_name_size; size -= arg_name_size;
data_to_string format_str(data, size); data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING #if FMT_FUZZ_FORMAT_TO_STRING
std::string message = std::string message =
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value)); fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
#else #else
fmt::memory_buffer out; fmt::memory_buffer out;
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value)); fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
#endif #endif
} catch (std::exception&) {
}
} }
// For dynamic dispatching to an explicit instantiation. // For dynamic dispatching to an explicit instantiation.
@ -91,11 +93,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
data++; data++;
size--; size--;
try { invoke(type, [=](auto arg) {
invoke(type, [=](auto arg) { invoke_fmt<decltype(arg)>(data, size, arg_name_size);
invoke_fmt<decltype(arg)>(data, size, arg_name_size); });
});
} catch (std::exception&) {
}
return 0; return 0;
} }

View File

@ -25,12 +25,15 @@ void invoke_fmt(const uint8_t* data, size_t size) {
data += fixed_size; data += fixed_size;
size -= fixed_size; size -= fixed_size;
data_to_string format_str(data, size); data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING #if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str.get(), *value); std::string message = fmt::format(format_str.get(), *value);
#else #else
fmt::memory_buffer message; fmt::memory_buffer message;
fmt::format_to(message, format_str.get(), *value); fmt::format_to(message, format_str.get(), *value);
#endif #endif
} catch (std::exception&) {
}
} }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
@ -40,54 +43,49 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
data++; data++;
size--; size--;
try { switch (first) {
switch (first) { case 0:
case 0: invoke_fmt<bool>(data, size);
invoke_fmt<bool>(data, size); break;
break; case 1:
case 1: invoke_fmt<char>(data, size);
invoke_fmt<char>(data, size); break;
break; case 2:
case 2: invoke_fmt<unsigned char>(data, size);
invoke_fmt<unsigned char>(data, size); break;
break; case 3:
case 3: invoke_fmt<signed char>(data, size);
invoke_fmt<signed char>(data, size); break;
break; case 4:
case 4: invoke_fmt<short>(data, size);
invoke_fmt<short>(data, size); break;
break; case 5:
case 5: invoke_fmt<unsigned short>(data, size);
invoke_fmt<unsigned short>(data, size); break;
break; case 6:
case 6: invoke_fmt<int>(data, size);
invoke_fmt<int>(data, size); break;
break; case 7:
case 7: invoke_fmt<unsigned int>(data, size);
invoke_fmt<unsigned int>(data, size); break;
break; case 8:
case 8: invoke_fmt<long>(data, size);
invoke_fmt<long>(data, size); break;
break; case 9:
case 9: invoke_fmt<unsigned long>(data, size);
invoke_fmt<unsigned long>(data, size); break;
break; case 10:
case 10: invoke_fmt<float>(data, size);
invoke_fmt<float>(data, size); break;
break; case 11:
case 11: invoke_fmt<double>(data, size);
invoke_fmt<double>(data, size); break;
break; case 12:
case 12: invoke_fmt<long double>(data, size);
invoke_fmt<long double>(data, size); break;
break; case 13:
case 13: invoke_fmt<std::tm, std::time_t>(data, size);
invoke_fmt<std::tm, std::time_t>(data, size); break;
break;
default:
break;
}
} catch (std::exception&) {
} }
return 0; return 0;
} }