Add float fuzzer and cleanup

This commit is contained in:
Victor Zverovich 2020-10-14 07:13:37 -07:00 committed by Victor Zverovich
parent 82c4e2236a
commit 010efc310f
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.
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)
get_filename_component(basename ${source} NAME_WE)
set(name ${basename}-fuzzer)
@ -23,6 +25,6 @@ function(add_fuzzer source)
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
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})
endforeach ()

View File

@ -1,7 +1,6 @@
#!/bin/sh
#
# 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)
# - libFuzzer build (you will need clang)
# - afl build (you will need afl)
@ -23,15 +22,6 @@ here=$(pwd)
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"
# 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.
builddir=$here/build-fuzzers-perfanalysis
mkdir -p $builddir
@ -68,18 +58,6 @@ cmake $CMAKEFLAGSALL \
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.
builddir=$here/build-fuzzers-fast
mkdir -p $builddir

View File

@ -81,6 +81,7 @@ void invoke_outer(const uint8_t* data, size_t size, int period) {
break;
case 15:
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:
invoke_outer<long double>(data, size, period);
break;
default:
break;
}
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
// For the license information refer to format.h.
#include <fmt/chrono.h>
#include <cstdint>
#include <type_traits>
#include <vector>
#include <fmt/chrono.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;
data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message =
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
std::string message =
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
#else
fmt::memory_buffer out;
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
fmt::memory_buffer out;
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
#endif
} catch (std::exception&) {
}
}
// For dynamic dispatching to an explicit instantiation.
@ -91,11 +93,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
data++;
size--;
try {
invoke(type, [=](auto arg) {
invoke_fmt<decltype(arg)>(data, size, arg_name_size);
});
} catch (std::exception&) {
}
invoke(type, [=](auto arg) {
invoke_fmt<decltype(arg)>(data, size, arg_name_size);
});
return 0;
}

View File

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