]> granicus.if.org Git - clang/commitdiff
Flag -fsanitize=fuzzer to enable libfuzzer
authorGeorge Karpenkov <ekarpenkov@apple.com>
Mon, 24 Apr 2017 18:23:24 +0000 (18:23 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Mon, 24 Apr 2017 18:23:24 +0000 (18:23 +0000)
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

include/clang/Basic/Sanitizers.def
include/clang/Driver/SanitizerArgs.h
lib/Driver/SanitizerArgs.cpp
lib/Driver/ToolChains/CommonArgs.cpp
lib/Driver/ToolChains/Darwin.cpp
lib/Driver/ToolChains/Darwin.h
lib/Driver/ToolChains/Linux.cpp
test/Driver/fuzzer.c [new file with mode: 0644]

index c574045e139a4c9246ace4cb81edf622d5291695..f20d326e08f84e4fca4f81804fa4f78411c72015 100644 (file)
@@ -47,6 +47,9 @@ SANITIZER("kernel-address", KernelAddress)
 // MemorySanitizer
 SANITIZER("memory", Memory)
 
+// libFuzzer
+SANITIZER("fuzzer", Fuzzer)
+
 // ThreadSanitizer
 SANITIZER("thread", Thread)
 
index 2df8077d6da6da6b6ee982bdb5c516db4f239387..c7b3e8006dd5ddbb4b887b94bf9918b5c3f73c8d 100644 (file)
@@ -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);
index 8e61aadbf3263f13a24ab8e697f2d68521ee1c8b..c9561367a3a87688117e992d880490f2e896810f 100644 (file)
@@ -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();
index 93b66eb6954a39aa2cdbb2fa069a20ea9d2b08d1..5e360f62e21ab132880d7a5c2ed191ccf0d891f8 100644 (file)
@@ -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)
index ec2212f7a80ff579367c6934e19c44ea25bf49c0..e41b50c40b2898f02ec47f940e3466b90d3051b5 100644 (file)
@@ -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;
index 984f8ef0c41fab550218ac2198ed034c173d6819..16ed04286ac06bda31cc95e9622b1e2460819cbf 100644 (file)
@@ -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 {
index 3ffb2f6e03e53a73b22b4553aad8588dee623474..50443a1252444e5776ff8c5110bcc37218b54b7d 100644 (file)
@@ -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 (file)
index 0000000..d60af98
--- /dev/null
@@ -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;
+}