diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:05:08 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:05:08 +0000 |
commit | 0646903fc1f75f6e605754621119473ee083f4a4 (patch) | |
tree | 57bce79a7423a054cccec23bdf6cd96e2d271b4a /lib/fuzzer | |
parent | 005b7ed8f76756d94ef6266ded755ab7863cb936 (diff) | |
download | src-0646903fc1f75f6e605754621119473ee083f4a4.tar.gz src-0646903fc1f75f6e605754621119473ee083f4a4.zip |
Vendor import of compiler-rt trunk r351319 (just before the release_80vendor/compiler-rt/compiler-rt-trunk-r351319vendor/compiler-rt/compiler-rt-release_80-r351543
branch point):
https://llvm.org/svn/llvm-project/compiler-rt/trunk@351319
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=343175
svn path=/vendor/compiler-rt/compiler-rt-release_80-r351543/; revision=343195; tag=vendor/compiler-rt/compiler-rt-release_80-r351543
Diffstat (limited to 'lib/fuzzer')
29 files changed, 357 insertions, 394 deletions
diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index 679318e460b5..caea9734fe53 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -3,8 +3,8 @@ set(LIBFUZZER_SOURCES FuzzerDataFlowTrace.cpp FuzzerDriver.cpp FuzzerExtFunctionsDlsym.cpp - FuzzerExtFunctionsDlsymWin.cpp FuzzerExtFunctionsWeak.cpp + FuzzerExtFunctionsWindows.cpp FuzzerExtraCounters.cpp FuzzerIO.cpp FuzzerIOPosix.cpp @@ -25,6 +25,8 @@ set(LIBFUZZER_SOURCES FuzzerUtilWindows.cpp) set(LIBFUZZER_HEADERS + FuzzerBuiltins.h + FuzzerBuiltinsMsvc.h FuzzerCommand.h FuzzerCorpus.h FuzzerDataFlowTrace.h @@ -124,12 +126,12 @@ if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH) set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch}) add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX} CFLAGS ${TARGET_CFLAGS} - -D_LIBCPP_ABI_VERSION=Fuzzer -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=1 -fvisibility=hidden CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON -DLIBCXX_ENABLE_EXCEPTIONS=OFF -DLIBCXX_ENABLE_SHARED=OFF + -DLIBCXX_ABI_NAMESPACE=Fuzzer -DLIBCXX_CXX_ABI=none) target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build) diff --git a/lib/fuzzer/FuzzerBuiltins.h b/lib/fuzzer/FuzzerBuiltins.h new file mode 100644 index 000000000000..a80938d9a54d --- /dev/null +++ b/lib/fuzzer/FuzzerBuiltins.h @@ -0,0 +1,36 @@ +//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Wrapper functions and marcos around builtin functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_BUILTINS_H +#define LLVM_FUZZER_BUILTINS_H + +#include "FuzzerDefs.h" + +#if !LIBFUZZER_MSVC +#include <cstdint> + +#define GET_CALLER_PC() __builtin_return_address(0) + +namespace fuzzer { + +inline uint8_t Bswap(uint8_t x) { return x; } +inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } +inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } +inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } + +inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); } +inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); } +inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); } + +} // namespace fuzzer + +#endif // !LIBFUZZER_MSVC +#endif // LLVM_FUZZER_BUILTINS_H diff --git a/lib/fuzzer/FuzzerBuiltinsMsvc.h b/lib/fuzzer/FuzzerBuiltinsMsvc.h new file mode 100644 index 000000000000..67dd57ff9a93 --- /dev/null +++ b/lib/fuzzer/FuzzerBuiltinsMsvc.h @@ -0,0 +1,59 @@ +//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Wrapper functions and marcos that use intrinsics instead of builtin functions +// which cannot be compiled by MSVC. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_BUILTINS_MSVC_H +#define LLVM_FUZZER_BUILTINS_MSVC_H + +#include "FuzzerDefs.h" + +#if LIBFUZZER_MSVC +#if !defined(_M_ARM) && !defined(_M_X64) +#error "_BitScanReverse64 unavailable on this platform so MSVC is unsupported." +#endif +#include <intrin.h> +#include <cstdint> +#include <cstdlib> + +// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent +// from <intrin.h> +#define GET_CALLER_PC() reinterpret_cast<uintptr_t>(_ReturnAddress()) + +namespace fuzzer { + +inline uint8_t Bswap(uint8_t x) { return x; } +// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on +// Windows since the builtins are not supported by MSVC. +inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); } +inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); } +inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); } + +// The functions below were mostly copied from +// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used +// outside of Windows. +inline uint32_t Clzll(uint64_t X) { + unsigned long LeadZeroIdx = 0; + if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx; + return 64; +} + +inline uint32_t Clz(uint32_t X) { + unsigned long LeadZeroIdx = 0; + if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx; + return 32; +} + +inline int Popcountll(unsigned long long X) { return __popcnt64(X); } + +} // namespace fuzzer + +#endif // LIBFUZER_MSVC +#endif // LLVM_FUZZER_BUILTINS_MSVC_H diff --git a/lib/fuzzer/FuzzerCommand.h b/lib/fuzzer/FuzzerCommand.h index 255f571ecf31..9d258a228f89 100644 --- a/lib/fuzzer/FuzzerCommand.h +++ b/lib/fuzzer/FuzzerCommand.h @@ -81,7 +81,7 @@ public: } // Like hasArgument, but checks for "-[Flag]=...". - bool hasFlag(const std::string &Flag) { + bool hasFlag(const std::string &Flag) const { std::string Arg("-" + Flag + "="); auto IsMatch = [&](const std::string &Other) { return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0; @@ -92,7 +92,7 @@ public: // Returns the value of the first instance of a given flag, or an empty string // if the flag isn't present. Ignores any occurrences after // "-ignore_remaining_args=1", if present. - std::string getFlagValue(const std::string &Flag) { + std::string getFlagValue(const std::string &Flag) const { std::string Arg("-" + Flag + "="); auto IsMatch = [&](const std::string &Other) { return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0; diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index 8ad14656cffc..f844c07c7572 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -238,12 +238,6 @@ class InputCorpus { return false; } - bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) { - assert(NewSize); - uint32_t OldSize = GetFeature(Idx % kFeatureSetSize); - return OldSize == 0 || (Shrink && OldSize > NewSize); - } - size_t NumFeatures() const { return NumAddedFeatures; } size_t NumFeatureUpdates() const { return NumUpdatedFeatures; } diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index a35c7a181b74..c3dccbcd86f5 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -82,6 +82,13 @@ #error "Support for your platform has not been implemented" #endif +#if defined(_MSC_VER) && !defined(__clang__) +// MSVC compiler is being used. +#define LIBFUZZER_MSVC 1 +#else +#define LIBFUZZER_MSVC 0 +#endif + #ifndef __has_attribute # define __has_attribute(x) 0 #endif @@ -129,8 +136,15 @@ #if LIBFUZZER_WINDOWS #define ATTRIBUTE_INTERFACE __declspec(dllexport) +// This is used for __sancov_lowest_stack which is needed for +// -fsanitize-coverage=stack-depth. That feature is not yet available on +// Windows, so make the symbol static to avoid linking errors. +#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \ + __attribute__((tls_model("initial-exec"))) thread_local static #else #define ATTRIBUTE_INTERFACE __attribute__((visibility("default"))) +#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \ + ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local #endif namespace fuzzer { @@ -176,11 +190,6 @@ typedef int (*UserCallback)(const uint8_t *Data, size_t Size); int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); -inline uint8_t Bswap(uint8_t x) { return x; } -inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } -inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } -inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } - uint8_t *ExtraCountersBegin(); uint8_t *ExtraCountersEnd(); void ClearExtraCounters(); diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 783474a39e16..ff2a639ac4a3 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -615,13 +615,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintNewCovPcs = Flags.print_pcs; Options.PrintNewCovFuncs = Flags.print_funcs; Options.PrintFinalStats = Flags.print_final_stats; - Options.PrintMutationStats = Flags.print_mutation_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; - Options.PrintUnstableStats = Flags.print_unstable_stats; - if (Flags.handle_unstable == TracePC::MinUnstable || - Flags.handle_unstable == TracePC::ZeroUnstable) - Options.HandleUnstable = Flags.handle_unstable; Options.DumpCoverage = Flags.dump_coverage; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp deleted file mode 100644 index 321b3ec5d414..000000000000 --- a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation using dynamic loading for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include "Windows.h" - -// This must be included after Windows.h. -#include "Psapi.h" - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { - HMODULE Modules[1024]; - DWORD BytesNeeded; - HANDLE CurrentProcess = GetCurrentProcess(); - - if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules), - &BytesNeeded)) { - Printf("EnumProcessModules failed (error: %d).\n", GetLastError()); - exit(1); - } - - if (sizeof(Modules) < BytesNeeded) { - Printf("Error: the array is not big enough to hold all loaded modules.\n"); - exit(1); - } - - for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++) - { - FARPROC Fn; -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - if (this->NAME == nullptr) { \ - Fn = GetProcAddress(Modules[i], #NAME); \ - if (Fn == nullptr) \ - Fn = GetProcAddress(Modules[i], #NAME "__dll"); \ - this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \ - } -#include "FuzzerExtFunctions.def" -#undef EXT_FUNC - } - -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - if (this->NAME == nullptr && WARN) \ - Printf("WARNING: Failed to find function \"%s\".\n", #NAME); -#include "FuzzerExtFunctions.def" -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp index a4e56fc27b8d..6a6ef4932f41 100644 --- a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp +++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp @@ -22,7 +22,7 @@ extern "C" { // Declare these symbols as weak to allow them to be optionally defined. #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG + __attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG #include "FuzzerExtFunctions.def" diff --git a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp deleted file mode 100644 index e10f7b4dcac2..000000000000 --- a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation using weak aliases. Works for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" - -using namespace fuzzer; - -extern "C" { -// Declare these symbols as weak to allow them to be optionally defined. -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - RETURN_TYPE NAME##Def FUNC_SIG { \ - Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ - exit(1); \ - } \ - RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def"))); - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -template <typename T> -static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) { - if (Fun == FunDef) { - if (WarnIfMissing) - Printf("WARNING: Failed to find function \"%s\".\n", FnName); - return nullptr; - } - return Fun; -} - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN); - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerExtFunctionsWindows.cpp b/lib/fuzzer/FuzzerExtFunctionsWindows.cpp new file mode 100644 index 000000000000..b01871439ca0 --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctionsWindows.cpp @@ -0,0 +1,83 @@ +//=== FuzzerExtWindows.cpp - Interface to external functions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation of FuzzerExtFunctions for Windows. Uses alternatename when +// compiled with MSVC. Uses weak aliases when compiled with clang. Unfortunately +// the method each compiler supports is not supported by the other. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" + +using namespace fuzzer; + +// Intermediate macro to ensure the parameter is expanded before stringified. +#define STRINGIFY_(A) #A +#define STRINGIFY(A) STRINGIFY_(A) + +#if LIBFUZZER_MSVC +// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h +#if defined(_M_IX86) || defined(__i386__) +#define WIN_SYM_PREFIX "_" +#else +#define WIN_SYM_PREFIX +#endif + +// Declare external functions as having alternativenames, so that we can +// determine if they are not defined. +#define EXTERNAL_FUNC(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \ + Name) "=" WIN_SYM_PREFIX STRINGIFY(Default))) +#else +// Declare external functions as weak to allow them to default to a specified +// function if not defined explicitly. We must use weak symbols because clang's +// support for alternatename is not 100%, see +// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details. +#define EXTERNAL_FUNC(Name, Default) \ + __attribute__((weak, alias(STRINGIFY(Default)))) +#endif // LIBFUZZER_MSVC + +extern "C" { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + } \ + EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG; + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +template <typename T> +static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) { + if (Fun == FunDef) { + if (WarnIfMissing) + Printf("WARNING: Failed to find function \"%s\".\n", FnName); + return nullptr; + } + return Fun; +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN); + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index ba04bc25fd45..91281c979c50 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -17,7 +17,7 @@ FUZZER_FLAG_INT(runs, -1, FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " "If 0, libFuzzer tries to guess a good value based on the corpus " "and reports it. ") -FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, " +FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, " "then try larger inputs over time. Specifies the rate at which the length " "limit is increased (smaller == faster). If 0, immediately try inputs with " "size up to max_len.") @@ -110,15 +110,6 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated." " If 1, dump coverage information as a" " .sancov file at exit.") -FUZZER_FLAG_INT(handle_unstable, 0, "Experimental." - " Executes every input 3 times in total if a unique feature" - " is found during the first execution." - " If 1, we only use the minimum hit count from the 3 runs" - " to determine whether an input is interesting." - " If 2, we disregard edges that are found unstable for" - " feature collection.") -FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental." - " If 1, print unstable statistics at exit.") FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") @@ -162,4 +153,3 @@ FUZZER_DEPRECATED_FLAG(use_equivalence_server) FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_DEPRECATED_FLAG(use_clang_coverage) FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace") -FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental") diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index f3ead0ec5357..c4c31e82471f 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -31,7 +31,7 @@ long GetEpoch(const std::string &Path) { } Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { - std::ifstream T(Path); + std::ifstream T(Path, std::ios::binary); if (ExitOnError && !T) { Printf("No such directory: %s; exiting\n", Path.c_str()); exit(1); @@ -51,7 +51,7 @@ Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { } std::string FileToString(const std::string &Path) { - std::ifstream T(Path); + std::ifstream T(Path, std::ios::binary); return std::string((std::istreambuf_iterator<char>(T)), std::istreambuf_iterator<char>()); } @@ -100,14 +100,6 @@ std::string DirPlusFile(const std::string &DirPath, return DirPath + GetSeparator() + FileName; } -std::string Basename(const std::string &Path, char Separator) { - size_t Pos = Path.rfind(Separator); - if (Pos == std::string::npos) - return Path; - assert(Pos < Path.size()); - return Path.substr(Pos + 1); -} - void DupAndCloseStderr() { int OutputFd = DuplicateFile(2); if (OutputFd > 0) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 6d7757435b7b..b4a68190e780 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V); char GetSeparator(); // Similar to the basename utility: returns the file name w/o the dir prefix. -std::string Basename(const std::string &Path, char Separator = GetSeparator()); +std::string Basename(const std::string &Path); FILE* OpenFile(int Fd, const char *Mode); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index 17e884d3c4c3..401b4cbbf74f 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -46,6 +46,13 @@ size_t FileSize(const std::string &Path) { return St.st_size; } +std::string Basename(const std::string &Path) { + size_t Pos = Path.rfind(GetSeparator()); + if (Pos == std::string::npos) return Path; + assert(Pos < Path.size()); + return Path.substr(Pos + 1); +} + void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector<std::string> *V, bool TopDir) { auto E = GetEpoch(Dir); diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp index 74853646b213..75dcaf72a940 100644 --- a/lib/fuzzer/FuzzerIOWindows.cpp +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -72,6 +72,26 @@ bool IsFile(const std::string &Path) { return IsFile(Path, Att); } +std::string Basename(const std::string &Path) { + size_t Pos = Path.find_last_of("/\\"); + if (Pos == std::string::npos) return Path; + assert(Pos < Path.size()); + return Path.substr(Pos + 1); +} + +size_t FileSize(const std::string &Path) { + WIN32_FILE_ATTRIBUTE_DATA attr; + if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) { + Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n", + Path.c_str(), GetLastError()); + return 0; + } + ULARGE_INTEGER size; + size.HighPart = attr.nFileSizeHigh; + size.LowPart = attr.nFileSizeLow; + return size.QuadPart; +} + void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector<std::string> *V, bool TopDir) { auto E = GetEpoch(Dir); @@ -91,7 +111,7 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, { if (GetLastError() == ERROR_FILE_NOT_FOUND) return; - Printf("No such directory: %s; exiting\n", Dir.c_str()); + Printf("No such file or directory: %s; exiting\n", Dir.c_str()); exit(1); } diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index bfc898248adb..a7fdc89cba5f 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -67,7 +67,6 @@ public: static void StaticGracefulExitCallback(); void ExecuteCallback(const uint8_t *Data, size_t Size); - void CheckForUnstableCounters(const uint8_t *Data, size_t Size); bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr); diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 4bc88365a0b9..a32a30723004 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -275,7 +275,8 @@ NO_SANITIZE_MEMORY void Fuzzer::AlarmCallback() { assert(Options.UnitTimeoutSec > 0); // In Windows Alarm callback is executed by a different thread. -#if !LIBFUZZER_WINDOWS + // NetBSD's current behavior needs this change too. +#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD if (!InFuzzingThread()) return; #endif @@ -354,13 +355,10 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { void Fuzzer::PrintFinalStats() { if (Options.PrintCoverage) TPC.PrintCoverage(); - if (Options.PrintUnstableStats) - TPC.PrintUnstableStats(); if (Options.DumpCoverage) TPC.DumpCoverage(); if (Options.PrintCorpusStats) Corpus.PrintStats(); - if (Options.PrintMutationStats) MD.PrintMutationStats(); if (!Options.PrintFinalStats) return; size_t ExecPerSec = execPerSec(); @@ -449,34 +447,6 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { } } -void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) { - auto CBSetupAndRun = [&]() { - ScopedEnableMsanInterceptorChecks S; - UnitStartTime = system_clock::now(); - TPC.ResetMaps(); - RunningUserCallback = true; - CB(Data, Size); - RunningUserCallback = false; - UnitStopTime = system_clock::now(); - }; - - // Copy original run counters into our unstable counters - TPC.InitializeUnstableCounters(); - - // First Rerun - CBSetupAndRun(); - TPC.UpdateUnstableCounters(Options.HandleUnstable); - - // Second Rerun - CBSetupAndRun(); - TPC.UpdateUnstableCounters(Options.HandleUnstable); - - // Move minimum hit counts back to ModuleInline8bitCounters - if (Options.HandleUnstable == TracePC::MinUnstable || - Options.HandleUnstable == TracePC::ZeroUnstable) - TPC.ApplyUnstableCounters(); -} - bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, InputInfo *II, bool *FoundUniqFeatures) { if (!Size) @@ -487,17 +457,6 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, UniqFeatureSetTmp.clear(); size_t FoundUniqFeaturesOfII = 0; size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); - bool NewFeaturesUnstable = false; - - if (Options.HandleUnstable || Options.PrintUnstableStats) { - TPC.CollectFeatures([&](size_t Feature) { - if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink)) - NewFeaturesUnstable = true; - }); - if (NewFeaturesUnstable) - CheckForUnstableCounters(Data, Size); - } - TPC.CollectFeatures([&](size_t Feature) { if (Corpus.AddFeature(Feature, Size, Options.Shrink)) UniqFeatureSetTmp.push_back(Feature); @@ -506,12 +465,10 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, II->UniqFeatureSet.end(), Feature)) FoundUniqFeaturesOfII++; }); - if (FoundUniqFeatures) *FoundUniqFeatures = FoundUniqFeaturesOfII; PrintPulseAndReportSlowInput(Data, Size); size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; - if (NumNewFeatures) { TPC.UpdateObservedPCs(); Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp index ff076cca683f..142b2b0b0014 100644 --- a/lib/fuzzer/FuzzerMutate.cpp +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -30,36 +30,34 @@ MutationDispatcher::MutationDispatcher(Random &Rand, DefaultMutators.insert( DefaultMutators.begin(), { - {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes", 0, 0}, - {&MutationDispatcher::Mutate_InsertByte, "InsertByte", 0, 0}, + {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, {&MutationDispatcher::Mutate_InsertRepeatedBytes, - "InsertRepeatedBytes", 0, 0}, - {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte", 0, 0}, - {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit", 0, 0}, - {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes", 0, 0}, - {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt", 0, - 0}, - {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt", 0, - 0}, - {&MutationDispatcher::Mutate_CopyPart, "CopyPart", 0, 0}, - {&MutationDispatcher::Mutate_CrossOver, "CrossOver", 0, 0}, + "InsertRepeatedBytes"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, + {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "ManualDict", 0, 0}, + "ManualDict"}, {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "PersAutoDict", 0, 0}, + "PersAutoDict"}, }); if(Options.UseCmp) DefaultMutators.push_back( - {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP", 0, 0}); + {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); if (EF->LLVMFuzzerCustomMutator) - Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom", 0, 0}); + Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); else Mutators = DefaultMutators; if (EF->LLVMFuzzerCustomCrossOver) Mutators.push_back( - {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver", 0, 0}); + {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); } static char RandCh(Random &Rand) { @@ -466,7 +464,6 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) PersistentAutoDictionary.push_back({DE->GetW(), 1}); } - RecordUsefulMutations(); } void MutationDispatcher::PrintRecommendedDictionary() { @@ -487,7 +484,8 @@ void MutationDispatcher::PrintRecommendedDictionary() { void MutationDispatcher::PrintMutationSequence() { Printf("MS: %zd ", CurrentMutatorSequence.size()); - for (auto M : CurrentMutatorSequence) Printf("%s-", M->Name); + for (auto M : CurrentMutatorSequence) + Printf("%s-", M.Name); if (!CurrentDictionaryEntrySequence.empty()) { Printf(" DE: "); for (auto DE : CurrentDictionaryEntrySequence) { @@ -515,13 +513,12 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 100; Iter++) { - auto M = &Mutators[Rand(Mutators.size())]; - size_t NewSize = (this->*(M->Fn))(Data, Size, MaxSize); + auto M = Mutators[Rand(Mutators.size())]; + size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize && NewSize <= MaxSize) { if (Options.OnlyASCII) ToASCII(Data, NewSize); CurrentMutatorSequence.push_back(M); - M->TotalCount++; return NewSize; } } @@ -562,21 +559,4 @@ void MutationDispatcher::AddWordToManualDictionary(const Word &W) { {W, std::numeric_limits<size_t>::max()}); } -void MutationDispatcher::RecordUsefulMutations() { - for (auto M : CurrentMutatorSequence) M->UsefulCount++; -} - -void MutationDispatcher::PrintMutationStats() { - Printf("\nstat::mutation_usefulness: "); - for (size_t i = 0; i < Mutators.size(); i++) { - double UsefulPercentage = - Mutators[i].TotalCount - ? (100.0 * Mutators[i].UsefulCount) / Mutators[i].TotalCount - : 0; - Printf("%.3f", UsefulPercentage); - if (i < Mutators.size() - 1) Printf(","); - } - Printf("\n"); -} - } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h index 828ecc13d866..a51c7fb44d46 100644 --- a/lib/fuzzer/FuzzerMutate.h +++ b/lib/fuzzer/FuzzerMutate.h @@ -93,16 +93,10 @@ public: Random &GetRand() { return Rand; } - void PrintMutationStats(); - - void RecordUsefulMutations(); - private: struct Mutator { size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); const char *Name; - uint64_t UsefulCount; - uint64_t TotalCount; }; size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, @@ -141,7 +135,6 @@ public: Dictionary PersistentAutoDictionary; Vector<DictionaryEntry *> CurrentDictionaryEntrySequence; - Vector<Mutator *> CurrentMutatorSequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; @@ -156,6 +149,7 @@ public: Vector<Mutator> Mutators; Vector<Mutator> DefaultMutators; + Vector<Mutator> CurrentMutatorSequence; }; } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index ce39c0876cd7..ab90df82a63d 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -52,11 +52,8 @@ struct FuzzingOptions { bool PrintNewCovPcs = false; int PrintNewCovFuncs = 0; bool PrintFinalStats = false; - bool PrintMutationStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; - bool PrintUnstableStats = false; - int HandleUnstable = 0; bool DumpCoverage = false; bool DetectLeaks = true; int PurgeAllocatorIntervalSec = 1; diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 29ffc8e34fc0..80b33105bb22 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "FuzzerTracePC.h" +#include "FuzzerBuiltins.h" +#include "FuzzerBuiltinsMsvc.h" #include "FuzzerCorpus.h" #include "FuzzerDefs.h" #include "FuzzerDictionary.h" @@ -32,8 +34,7 @@ ATTRIBUTE_INTERFACE uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; // Used by -fsanitize-coverage=stack-depth to track stack depth -ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) -thread_local uintptr_t __sancov_lowest_stack; +ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack; namespace fuzzer { @@ -57,49 +58,6 @@ size_t TracePC::GetTotalPCCoverage() { return Res; } -template<class CallBack> -void TracePC::IterateInline8bitCounters(CallBack CB) const { - if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) { - size_t CounterIdx = 0; - for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { - uint8_t *Beg = ModuleCounters[i].Start; - size_t Size = ModuleCounters[i].Stop - Beg; - assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); - for (size_t j = 0; j < Size; j++, CounterIdx++) - CB(i, j, CounterIdx); - } - } -} - -// Initializes unstable counters by copying Inline8bitCounters to unstable -// counters. -void TracePC::InitializeUnstableCounters() { - IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { - UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j]; - }); -} - -// Compares the current counters with counters from previous runs -// and records differences as unstable edges. -void TracePC::UpdateUnstableCounters(int UnstableMode) { - IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { - if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) { - UnstableCounters[UnstableIdx].IsUnstable = true; - if (UnstableMode == ZeroUnstable) - UnstableCounters[UnstableIdx].Counter = 0; - else if (UnstableMode == MinUnstable) - UnstableCounters[UnstableIdx].Counter = std::min( - ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter); - } - }); -} - -// Moves the minimum hit counts to ModuleCounters. -void TracePC::ApplyUnstableCounters() { - IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { - ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter; - }); -} void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { if (Start == Stop) return; @@ -185,11 +143,42 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { ValueProfileMap.AddValueModPrime(Idx); } +/// \return the address of the previous instruction. +/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.h` +inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { +#if defined(__arm__) + // T32 (Thumb) branch instructions might be 16 or 32 bit long, + // so we return (pc-2) in that case in order to be safe. + // For A32 mode we return (pc-4) because all instructions are 32 bit long. + return (PC - 3) & (~1); +#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__) + // PCs are always 4 byte aligned. + return PC - 4; +#elif defined(__sparc__) || defined(__mips__) + return PC - 8; +#else + return PC - 1; +#endif +} + +/// \return the address of the next instruction. +/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cc` +inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) { +#if defined(__mips__) + return PC + 8; +#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \ + defined(__aarch64__) + return PC + 4; +#else + return PC + 1; +#endif +} + void TracePC::UpdateObservedPCs() { Vector<uintptr_t> CoveredFuncs; auto ObservePC = [&](uintptr_t PC) { if (ObservedPCs.insert(PC).second && DoPrintNewPCs) { - PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1); + PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", GetNextInstructionPc(PC)); Printf("\n"); } }; @@ -203,10 +192,15 @@ void TracePC::UpdateObservedPCs() { if (NumPCsInPCTables) { if (NumInline8bitCounters == NumPCsInPCTables) { - IterateInline8bitCounters([&](int i, int j, int CounterIdx) { - if (ModuleCounters[i].Start[j]) - Observe(ModulePCTable[i].Start[j]); - }); + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + uint8_t *Beg = ModuleCounters[i].Start; + size_t Size = ModuleCounters[i].Stop - Beg; + assert(Size == + (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); + for (size_t j = 0; j < Size; j++) + if (Beg[j]) + Observe(ModulePCTable[i].Start[j]); + } } else if (NumGuards == NumPCsInPCTables) { size_t GuardIdx = 1; for (size_t i = 0; i < NumModules; i++) { @@ -224,22 +218,11 @@ void TracePC::UpdateObservedPCs() { for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) { Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size()); - PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1); + PrintPC("%p %F %L", "%p", GetNextInstructionPc(CoveredFuncs[i])); Printf("\n"); } } -inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { - // TODO: this implementation is x86 only. - // see sanitizer_common GetPreviousInstructionPc for full implementation. - return PC - 1; -} - -inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) { - // TODO: this implementation is x86 only. - // see sanitizer_common GetPreviousInstructionPc for full implementation. - return PC + 1; -} static std::string GetModuleName(uintptr_t PC) { char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++? @@ -349,15 +332,6 @@ void TracePC::DumpCoverage() { } } -void TracePC::PrintUnstableStats() { - size_t count = 0; - for (size_t i = 0; i < NumInline8bitCounters; i++) - if (UnstableCounters[i].IsUnstable) - count++; - Printf("stat::stability_rate: %.2f\n", - 100 - static_cast<float>(count * 100) / NumInline8bitCounters); -} - // Value profile. // We keep track of various values that affect control flow. // These values are inserted into a bit-set-based hash map. @@ -401,20 +375,14 @@ ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE ATTRIBUTE_NO_SANITIZE_ALL void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { uint64_t ArgXor = Arg1 ^ Arg2; - uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65] - uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance; if (sizeof(T) == 4) TORC4.Insert(ArgXor, Arg1, Arg2); else if (sizeof(T) == 8) TORC8.Insert(ArgXor, Arg1, Arg2); - // TODO: remove these flags and instead use all metrics at once. - if (UseValueProfileMask & 1) - ValueProfileMap.AddValue(Idx); - if (UseValueProfileMask & 2) - ValueProfileMap.AddValue( - PC * 64 + (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1)); - if (UseValueProfileMask & 4) // alternative way to use the hamming distance - ValueProfileMap.AddValue(PC * 64 + ArgDistance); + uint64_t HammingDistance = Popcountll(ArgXor); // [0,64] + uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1); + ValueProfileMap.AddValue(PC * 128 + HammingDistance); + ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); } static size_t InternalStrnlen(const char *S, size_t MaxLen) { @@ -455,7 +423,7 @@ extern "C" { ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); uint32_t Idx = *Guard; __sancov_trace_pc_pcs[Idx] = PC; __sancov_trace_pc_guard_8bit_counters[Idx]++; @@ -466,7 +434,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc() { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1); __sancov_trace_pc_pcs[Idx] = PC; __sancov_trace_pc_guard_8bit_counters[Idx]++; @@ -491,7 +459,7 @@ void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCallerCallee(PC, Callee); } @@ -499,7 +467,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -510,7 +478,7 @@ ATTRIBUTE_TARGET_POPCNT // the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however, // should be changed later to make full use of instrumentation. void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -518,7 +486,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -526,7 +494,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -534,7 +502,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -542,7 +510,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -550,7 +518,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -558,7 +526,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -572,7 +540,7 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { // Skip the most common and the most boring case. if (Vals[N - 1] < 256 && Val < 256) return; - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); size_t i; uint64_t Token = 0; for (i = 0; i < N; i++) { @@ -593,7 +561,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_div4(uint32_t Val) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); } @@ -601,7 +569,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_div8(uint64_t Val) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); } @@ -609,7 +577,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_gep(uintptr_t Idx) { - uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); } diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 097ba69bdc08..46d6c24887fd 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -74,11 +74,6 @@ class TracePC { // How many bits of PC are used from __sanitizer_cov_trace_pc. static const size_t kTracePcBits = 18; - enum HandleUnstableOptions { - MinUnstable = 1, - ZeroUnstable = 2, - }; - void HandleInit(uint32_t *Start, uint32_t *Stop); void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop); @@ -109,7 +104,6 @@ class TracePC { void PrintCoverage(); void DumpCoverage(); - void PrintUnstableStats(); template<class CallBack> void IterateCoveredFunctions(CallBack CB); @@ -142,18 +136,7 @@ class TracePC { void SetFocusFunction(const std::string &FuncName); bool ObservedFocusFunction(); - void InitializeUnstableCounters(); - void UpdateUnstableCounters(int UnstableMode); - void ApplyUnstableCounters(); - private: - struct UnstableEdge { - uint8_t Counter; - bool IsUnstable; - }; - - UnstableEdge UnstableCounters[kNumPCs]; - bool UseCounters = false; uint32_t UseValueProfileMask = false; bool DoPrintNewPCs = false; @@ -185,9 +168,6 @@ private: Set<uintptr_t> ObservedPCs; std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs; // PC => Counter. - template <class Callback> - void IterateInline8bitCounters(Callback CB) const; - std::pair<size_t, size_t> FocusFunction = {-1, -1}; // Module and PC IDs. ValueBitMap ValueProfileMap; diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index 8c5c57c3ab83..d2f1d5de4267 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -12,8 +12,10 @@ #ifndef LLVM_FUZZER_UTIL_H #define LLVM_FUZZER_UTIL_H -#include "FuzzerDefs.h" +#include "FuzzerBuiltins.h" +#include "FuzzerBuiltinsMsvc.h" #include "FuzzerCommand.h" +#include "FuzzerDefs.h" namespace fuzzer { @@ -84,7 +86,7 @@ std::string SearchRegexCmd(const std::string &Regex); size_t SimpleFastHash(const uint8_t *Data, size_t Size); -inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; } +inline uint32_t Log(uint32_t X) { return 32 - Clz(X) - 1; } } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp index cd2bb7438e9d..cd48fefef352 100644 --- a/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp @@ -49,9 +49,6 @@ void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); namespace { -// TODO(phosek): remove this and replace it with ZX_TIME_INFINITE -#define ZX_TIME_INFINITE_OLD INT64_MAX - // A magic value for the Zircon exception port, chosen to spell 'FUZZING' // when interpreted as a byte sequence on little-endian platforms. const uint64_t kFuzzingCrash = 0x474e495a5a5546; @@ -237,7 +234,7 @@ void CrashHandler(zx_handle_t *Event) { "_zx_object_signal"); zx_port_packet_t Packet; - ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE_OLD, &Packet), + ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE, &Packet), "_zx_port_wait"); // At this point, we want to get the state of the crashing thread, but @@ -315,8 +312,8 @@ void SetSignalHandler(const FuzzingOptions &Options) { ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); std::thread T(CrashHandler, &Event); - zx_status_t Status = _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, - ZX_TIME_INFINITE_OLD, nullptr); + zx_status_t Status = + _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr); _zx_handle_close(Event); ExitOnErr(Status, "_zx_object_wait_one"); @@ -378,19 +375,28 @@ int ExecuteCommand(const Command &Cmd) { Argv[i] = Args[i].c_str(); Argv[Argc] = nullptr; - // Determine stdout + // Determine output. On Fuchsia, the fuzzer is typically run as a component + // that lacks a mutable working directory. Fortunately, when this is the case + // a mutable output directory must be specified using "-artifact_prefix=...", + // so write the log file(s) there. int FdOut = STDOUT_FILENO; - if (Cmd.hasOutputFile()) { - auto Filename = Cmd.getOutputFile(); - FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); + std::string Path; + if (Cmd.hasFlag("artifact_prefix")) + Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile(); + else + Path = Cmd.getOutputFile(); + FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); if (FdOut == -1) { - Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(), + Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(), strerror(errno)); return ZX_ERR_IO; } } - auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } ); + auto CloseFdOut = at_scope_exit([FdOut]() { + if (FdOut != STDOUT_FILENO) + close(FdOut); + }); // Determine stderr int FdErr = STDERR_FILENO; @@ -440,7 +446,7 @@ int ExecuteCommand(const Command &Cmd) { // Now join the process and return the exit status. if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, - ZX_TIME_INFINITE_OLD, nullptr)) != ZX_OK) { + ZX_TIME_INFINITE, nullptr)) != ZX_OK) { Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], _zx_status_get_string(rc)); return rc; diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp index 8227e778ea0a..393b4768be7e 100644 --- a/lib/fuzzer/FuzzerUtilWindows.cpp +++ b/lib/fuzzer/FuzzerUtilWindows.cpp @@ -24,7 +24,7 @@ #include <windows.h> // This must be included after windows.h. -#include <Psapi.h> +#include <psapi.h> namespace fuzzer { @@ -179,7 +179,9 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, } std::string DisassembleCmd(const std::string &FileName) { - if (ExecuteCommand("dumpbin /summary > nul") == 0) + Vector<std::string> command_vector; + command_vector.push_back("dumpbin /summary > nul"); + if (ExecuteCommand(Command(command_vector)) == 0) return "dumpbin /disasm " + FileName; Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); exit(1); diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index fa494c03bde0..5a10c0d27f3a 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -289,7 +289,7 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { // Execute any files provided as parameters. int ExecuteFilesOnyByOne(int argc, char **argv) { for (int i = 1; i < argc; i++) { - std::ifstream in(argv[i]); + std::ifstream in(argv[i], std::ios::binary); in.seekg(0, in.end); size_t length = in.tellg(); in.seekg (0, in.beg); diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt index ed5807168301..6abb72def3e1 100644 --- a/lib/fuzzer/tests/CMakeLists.txt +++ b/lib/fuzzer/tests/CMakeLists.txt @@ -1,3 +1,5 @@ +include(CompilerRTCompile) + set(LIBFUZZER_UNITTEST_CFLAGS ${COMPILER_RT_UNITTEST_CFLAGS} ${COMPILER_RT_GTEST_CFLAGS} @@ -17,12 +19,12 @@ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++) if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread) -else() +elseif(NOT WIN32) list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread) endif() if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH) - list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer) + list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++) endif() if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH) @@ -45,7 +47,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH) set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build) - set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${COMPILER_RT_LIBCXX_PATH}/include) + set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a) endif() diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index e3b06702603d..7cdd44582329 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -34,6 +34,13 @@ TEST(Fuzzer, Basename) { EXPECT_EQ(Basename("/bar"), "bar"); EXPECT_EQ(Basename("foo/x"), "x"); EXPECT_EQ(Basename("foo/"), ""); +#if LIBFUZZER_WINDOWS + EXPECT_EQ(Basename("foo\\bar"), "bar"); + EXPECT_EQ(Basename("foo\\bar/baz"), "baz"); + EXPECT_EQ(Basename("\\bar"), "bar"); + EXPECT_EQ(Basename("foo\\x"), "x"); + EXPECT_EQ(Basename("foo\\"), ""); +#endif } TEST(Fuzzer, CrossOver) { |