From: George Karpenkov Date: Mon, 24 Apr 2017 18:23:24 +0000 (+0000) Subject: Flag -fsanitize=fuzzer to enable libfuzzer X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3efd04e48004628cfaffead00ecb1c206b0b6cb2;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301212 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def index c574045e13..f20d326e08 100644 --- a/include/clang/Basic/Sanitizers.def +++ b/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/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h index 2df8077d6d..c7b3e8006d 100644 --- a/include/clang/Driver/SanitizerArgs.h +++ b/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/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 8e61aadbf3..c9561367a3 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/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/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index 93b66eb695..5e360f62e2 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/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/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index ec2212f7a8..e41b50c40b 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/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/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index 984f8ef0c4..16ed04286a 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/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/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 3ffb2f6e03..50443a1252 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/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/test/Driver/fuzzer.c b/test/Driver/fuzzer.c new file mode 100644 index 0000000000..d60af988a2 --- /dev/null +++ b/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; +}