This commit is contained in:
Victor Zverovich 2020-10-11 08:30:14 -07:00
parent 48ea8193df
commit af28305961
11 changed files with 35 additions and 87 deletions

View File

@ -330,7 +330,13 @@ endif ()
# Control fuzzing independent of the unit tests. # Control fuzzing independent of the unit tests.
if (FMT_FUZZ) if (FMT_FUZZ)
add_subdirectory(test/fuzzing) 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 () endif ()
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore) set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)

View File

@ -5,19 +5,10 @@
// //
// For the license information refer to format.h. // For the license information refer to format.h.
#include <stdint.h>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
#include <deque>
#include <list>
#include <memory>
#include <string> #include <string>
#include <type_traits>
// 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 #ifdef _WIN32
# include <windows.h> # include <windows.h>
#endif #endif
@ -25,16 +16,8 @@
#include "fmt/compile.h" #include "fmt/compile.h"
#include "gmock.h" #include "gmock.h"
#include "gtest-extra.h" #include "gtest-extra.h"
#include "mock-allocator.h"
#include "util.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 // compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr. // constexpr.
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR

View File

@ -1,6 +0,0 @@
// Copyright (c) 2020 Vladimir Solontsov
// SPDX-License-Identifier: MIT Licence
#include <fmt/core.h>
#include "gtest-extra.h"

View File

@ -1,37 +1,28 @@
# Copyright (c) 2019, Paul Dreik # Copyright (c) 2019, Paul Dreik
# License: see LICENSE.rst in the fmt root directory # License: see LICENSE.rst in the fmt root directory
# settings this links in a main. useful for reproducing, # Link in the main function. Useful for reproducing, kcov, gdb, afl, valgrind.
# kcov, gdb, afl, valgrind. # (Note that libFuzzer can also reproduce, just pass it the files.)
# (note that libFuzzer can also reproduce, just pass it the files) option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On)
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 # 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") set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets")
# Find all fuzzers. function(add_fuzzer source)
set(SOURCES get_filename_component(basename ${source} NAME_WE)
chrono_duration.cpp
named_arg.cpp
one_arg.cpp
two_args.cpp
)
macro(implement_fuzzer sourcefile)
get_filename_component(basename ${sourcefile} NAME_WE)
set(name fuzzer_${basename}) set(name fuzzer_${basename})
add_executable(${name} ${sourcefile} fuzzer_common.h) add_executable(${name} ${source} fuzzer-common.h)
if (FMT_FUZZ_LINKMAIN) if (FMT_FUZZ_LINKMAIN)
target_sources(${name} PRIVATE main.cpp) target_sources(${name} PRIVATE main.cc)
endif () endif ()
target_link_libraries(${name} PRIVATE fmt) target_link_libraries(${name} PRIVATE fmt)
if (FMT_FUZZ_LDFLAGS) if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS}) target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif () endif ()
target_compile_features(${name} PRIVATE cxx_generic_lambdas) target_compile_features(${name} PRIVATE cxx_generic_lambdas)
endmacro () endfunction()
foreach (X IN ITEMS ${SOURCES}) foreach (source chrono-duration.cc named-arg.cc one-arg.cc two-args.cc)
implement_fuzzer(${X}) add_fuzzer(${source})
endforeach () endforeach ()

View File

@ -1,27 +1,4 @@
# FMT Fuzzer # Running the fuzzers locally
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
There is a [helper script](build.sh) to build the fuzzers, which has only been 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 tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on

View File

@ -4,11 +4,11 @@
#include <cstdint> #include <cstdint>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include "fuzzer_common.h" #include "fuzzer-common.h"
template <typename Item, typename Ratio> template <typename Item, typename Ratio>
void invoke_inner(fmt::string_view format_str, const Item item) { void invoke_inner(fmt::string_view format_str, Item item) {
const std::chrono::duration<Item, Ratio> value(item); auto value = std::chrono::duration<Item, Ratio>(item);
try { try {
#if FMT_FUZZ_FORMAT_TO_STRING #if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, value); std::string message = fmt::format(format_str, value);

View File

@ -2,7 +2,7 @@
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include "fuzzer_common.h" #include "fuzzer-common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);

View File

@ -6,7 +6,7 @@
#include <vector> #include <vector>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include "fuzzer_common.h" #include "fuzzer-common.h"
template <typename Item1> template <typename Item1>
void invoke_fmt(const uint8_t* data, size_t size, unsigned int argsize) { void invoke_fmt(const uint8_t* data, size_t size, unsigned int argsize) {

View File

@ -7,7 +7,7 @@
#include <vector> #include <vector>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include "fuzzer_common.h" #include "fuzzer-common.h"
using fmt_fuzzer::nfixed; using fmt_fuzzer::nfixed;
@ -15,9 +15,7 @@ template <typename Item>
void invoke_fmt(const uint8_t* data, size_t size) { void invoke_fmt(const uint8_t* data, size_t size) {
constexpr auto N = sizeof(Item); constexpr auto N = sizeof(Item);
static_assert(N <= nfixed, "Nfixed is too small"); static_assert(N <= nfixed, "Nfixed is too small");
if (size <= nfixed) { if (size <= nfixed) return;
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(data); const Item item = fmt_fuzzer::assignFromBuf<Item>(data);
data += nfixed; data += nfixed;
size -= nfixed; size -= nfixed;

View File

@ -6,12 +6,11 @@
#include <string> #include <string>
#include <fmt/format.h> #include <fmt/format.h>
#include "fuzzer_common.h" #include "fuzzer-common.h"
constexpr auto nfixed = fmt_fuzzer::nfixed;
template <typename Item1, typename Item2> template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* data, size_t size) { void invoke_fmt(const uint8_t* data, size_t size) {
using fmt_fuzzer::nfixed;
static_assert(sizeof(Item1) <= nfixed, "size1 exceeded"); static_assert(sizeof(Item1) <= nfixed, "size1 exceeded");
static_assert(sizeof(Item2) <= nfixed, "size2 exceeded"); static_assert(sizeof(Item2) <= nfixed, "size2 exceeded");
if (size <= nfixed + nfixed) return; if (size <= nfixed + nfixed) return;