From f2fc5b068e011455a4857cdc9349055c5a8b5221 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 24 Apr 2017 18:23:24 +0000 Subject: [PATCH] Flag -fsanitize=fuzzer to enable libfuzzer Previously, adding libfuzzer to a project was a multi-step procedure, involving libfuzzer compilation, linking the library, and specifying coverage flags. With this change,libfuzzer can be enabled by adding a single -fsanitize=fuzzer flag instead. llvm-svn: 301212 --- clang/include/clang/Basic/Sanitizers.def | 3 +++ clang/include/clang/Driver/SanitizerArgs.h | 1 + clang/lib/Driver/SanitizerArgs.cpp | 4 ++++ clang/lib/Driver/ToolChains/CommonArgs.cpp | 16 ++++++++++++++++ clang/lib/Driver/ToolChains/Darwin.cpp | 15 +++++++++++++++ clang/lib/Driver/ToolChains/Darwin.h | 2 ++ clang/lib/Driver/ToolChains/Linux.cpp | 1 + clang/test/Driver/fuzzer.c | 22 ++++++++++++++++++++++ 8 files changed, 64 insertions(+) create mode 100644 clang/test/Driver/fuzzer.c diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c574045e139a..f20d326e08f8 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -47,6 +47,9 @@ SANITIZER("kernel-address", KernelAddress) // MemorySanitizer SANITIZER("memory", Memory) +// libFuzzer +SANITIZER("fuzzer", Fuzzer) + // ThreadSanitizer SANITIZER("thread", Thread) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 2df8077d6da6..c7b3e8006dd5 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -50,6 +50,7 @@ class SanitizerArgs { bool needsSharedAsanRt() const { return AsanSharedRuntime; } bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } + bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); } bool needsLsanRt() const { return Sanitizers.has(SanitizerKind::Leak) && !Sanitizers.has(SanitizerKind::Address); diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 8e61aadbf326..c9561367a3a8 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -265,6 +265,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Add &= ~InvalidTrappingKinds; Add &= Supported; + // Enable coverage if the fuzzing flag is set. + if (Add & Fuzzer) + CoverageFeatures |= CoverageTracePCGuard | CoverageIndirCall | CoverageTraceCmp; + Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { Arg->claim(); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 93b66eb6954a..5e360f62e21a 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -577,6 +577,17 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("esan"); } +static void addLibFuzzerRuntime(const ToolChain &TC, + const ArgList &Args, + ArgStringList &CmdArgs) { + StringRef ParentDir = llvm::sys::path::parent_path(TC.getDriver().InstalledDir); + SmallString<128> P(ParentDir); + llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); + CmdArgs.push_back(Args.MakeArgString(P)); + TC.AddCXXStdlibLibArgs(Args, CmdArgs); +} + + // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, @@ -586,6 +597,11 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); + // Inject libfuzzer dependencies. + if (TC.getSanitizerArgs().needsFuzzer()) { + addLibFuzzerRuntime(TC, Args, CmdArgs); + } + for (auto RT : SharedRuntimes) addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); for (auto RT : HelperStaticRuntimes) diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index ec2212f7a80f..e41b50c40b28 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -930,6 +930,18 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, } } +void MachO::AddFuzzerLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + + // Go up one directory from Clang to find the libfuzzer archive file. + StringRef ParentDir = llvm::sys::path::parent_path(getDriver().InstalledDir); + SmallString<128> P(ParentDir); + llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); + CmdArgs.push_back(Args.MakeArgString(P)); + + // Libfuzzer is written in C++ and requires libcxx. + AddCXXStdlibLibArgs(Args, CmdArgs); +} + StringRef Darwin::getPlatformFamily() const { switch (TargetPlatform) { case DarwinPlatformKind::MacOS: @@ -1041,6 +1053,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + if (Sanitize.needsFuzzer()) + AddFuzzerLinkArgs(Args, CmdArgs); if (Sanitize.needsStatsRt()) { StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib(Args, CmdArgs, @@ -1895,6 +1909,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::Leak; + Res |= SanitizerKind::Fuzzer; if (isTargetMacOS()) { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 984f8ef0c41f..16ed04286ac0 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -154,6 +154,8 @@ public: /// Add the linker arguments to link the compiler runtime library. virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + virtual void AddFuzzerLinkArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 3ffb2f6e03e5..50443a125244 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -869,6 +869,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { llvm::Triple::thumbeb; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; diff --git a/clang/test/Driver/fuzzer.c b/clang/test/Driver/fuzzer.c new file mode 100644 index 000000000000..d60af988a24a --- /dev/null +++ b/clang/test/Driver/fuzzer.c @@ -0,0 +1,22 @@ +// Test flags inserted by -fsanitize=fuzzer. + +// RUN: %clang -fsanitize=fuzzer %s -### 2>&1 | FileCheck --check-prefixes=CHECK-FUZZER-LIB,CHECK-COVERAGE-FLAGS %s +// +// CHECK-FUZZER-LIB: libLLVMFuzzer.a +// CHECK-COVERAGE: -fsanitize-coverage-trace-pc-guard +// CHECK-COVERAGE-SAME: -fsanitize-coverage-indirect-calls +// CHECK-COVERAGE-SAME: -fsanitize-coverage-trace-cmp + +// RUN: %clang -fsanitize=fuzzer -target i386-unknown-linux %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LIBCXX-LINUX %s +// +// CHECK-LIBCXX-LINUX: -lstdc++ + +// RUN: %clang -target x86_64-apple-darwin14 -fsanitize=fuzzer %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LIBCXX-DARWIN %s +// +// CHECK-LIBCXX-DARWIN: -lc++ + +// RUN: %clang -fsanitize=fuzzer %s + +int LLVMFuzzerTestOneInput(const char *Data, long Size) { + return 0; +}