]> granicus.if.org Git - clang/commitdiff
Add -fsanitize=<sanitizers> argument to driver and frontend, and add
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 5 Nov 2012 22:04:41 +0000 (22:04 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 5 Nov 2012 22:04:41 +0000 (22:04 +0000)
-fno-sanitize=<sanitizers> argument to driver. These allow ASan, TSan, and the
various UBSan checks to be enabled and disabled separately. Right now, the
different modes can't be combined, but the intention is that combining UBSan
and the other sanitizers will be permitted in the near future.

Currently, the UBSan checks will all be enabled if any of them is; that will be
fixed by the next patch.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167411 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/LangOptions.def
include/clang/Basic/Sanitizers.def [new file with mode: 0644]
include/clang/Driver/Options.td
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
test/Driver/asan-ld.c
test/Driver/asan.c
test/Driver/darwin-asan-nofortify.c
test/Driver/fsanitize.c [new file with mode: 0644]
test/Driver/tsan.c

index 7bce57352ab891f04ca22e66945bcf372d46ddfe..fab4a5464067572a61098e0a6d4b28fa9941c0c9 100644 (file)
@@ -127,8 +127,6 @@ BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
 BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
 BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type")
 BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and subscripting support")
-BENIGN_LANGOPT(SanitizeAddress , 1, 0, "AddressSanitizer enabled")
-BENIGN_LANGOPT(SanitizeThread , 1, 0, "ThreadSanitizer enabled")
 
 BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
 LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
@@ -170,6 +168,11 @@ BENIGN_LANGOPT(EmitMicrosoftInlineAsm , 1, 0,
 
 BENIGN_LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
 
+/// Runtime sanitizers.
+#define SANITIZER(NAME, ID) \
+BENIGN_LANGOPT(Sanitize##ID, 1, 0, NAME " sanitizer")
+#include "clang/Basic/Sanitizers.def"
+
 #undef LANGOPT
 #undef VALUE_LANGOPT
 #undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
new file mode 100644 (file)
index 0000000..085ca16
--- /dev/null
@@ -0,0 +1,69 @@
+//===--- Sanitizers.def - Runtime sanitizer options -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the options for specifying which runtime sanitizers to
+// enable. Users of this file must define the SANITIZER macro to make use of
+// this information. Users of this file can also define the SANITIZER_GROUP
+// macro to get information on options which refer to sets of sanitizers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER
+#error "Define SANITIZER prior to including this file!"
+#endif
+
+// SANITIZER(NAME, ID)
+
+// The first value is the name of the sanitizer as a string. The sanitizer can
+// be enabled by specifying -fsanitize=NAME.
+
+// The second value is an identifier which can be used to refer to the
+// sanitizer.
+
+
+// SANITIZER_GROUP(NAME, ID, ALIAS)
+
+// The first two values have the same semantics as the corresponding SANITIZER
+// values. The third value is an expression ORing together the IDs of individual
+// sanitizers in this group.
+
+#ifndef SANITIZER_GROUP
+#define SANITIZER_GROUP(NAME, ID, ALIAS)
+#endif
+
+
+// AddressSanitizer
+SANITIZER("address", Address)
+
+// ThreadSanitizer
+SANITIZER("thread", Thread)
+
+// UndefinedBehaviorSanitizer
+SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
+SANITIZER("divide-by-zero", DivideByZero)
+SANITIZER("shift", Shift)
+SANITIZER("unreachable", Unreachable)
+SANITIZER("return", Return)
+SANITIZER("vla-bound", VLABound)
+SANITIZER("alignment", Alignment)
+SANITIZER("null", Null)
+SANITIZER("vptr", Vptr)
+SANITIZER("object-size", ObjectSize)
+SANITIZER("float-cast-overflow", FloatCastOverflow)
+
+// -fsanitize=undefined (and its alias -fcatch-undefined-behavior). This should
+// include all the sanitizers which have low overhead, no ABI or address space
+// layout implications, and only catch undefined behavior.
+SANITIZER_GROUP("undefined", Undefined,
+                SignedIntegerOverflow | DivideByZero | Shift | Unreachable |
+                Return | VLABound | Alignment | Null | Vptr | ObjectSize |
+                FloatCastOverflow)
+
+#undef SANITIZER
+#undef SANITIZER_GROUP
index 3c39eb66e7260e22e731b85b081107d75b193e14..ba609faab47bbe372ebcb855faf7be8ecefd5df3 100644 (file)
@@ -387,6 +387,9 @@ def fmath_errno : Flag<["-"], "fmath-errno">, Group<f_Group>, Flags<[CC1Option]>
 def fno_math_errno : Flag<["-"], "fno-math-errno">, Group<f_Group>;
 def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>;
 def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
+def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
+                   Flags<[CC1Option]>;
+def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>;
 def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
   Group<f_Group>;
 def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
index 05487c4193d3d9c3d8705bdce0b5545007783f32..d1109ff7302df9233b2f93803bb53a0028005dca 100644 (file)
@@ -1452,13 +1452,149 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
     RelaxDefault);
 }
 
+namespace {
+struct SanitizerArgs {
+  /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
+  /// bit positions within \c Kind.
+  enum SanitizeOrdinal {
+#define SANITIZER(NAME, ID) SO_##ID,
+#include "clang/Basic/Sanitizers.def"
+    SO_Count
+  };
+
+  /// Bugs to catch at runtime.
+  enum SanitizeKind {
+#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
+#include "clang/Basic/Sanitizers.def"
+
+    NeedsAsanRt = Address,
+    NeedsTsanRt = Thread,
+    NeedsUbsanRt = Undefined
+  };
+  unsigned Kind;
+
+  SanitizerArgs() : Kind(0) {}
+
+  bool needsAsanRt() const { return Kind & NeedsAsanRt; }
+  bool needsTsanRt() const { return Kind & NeedsTsanRt; }
+  bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
+
+  /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
+  /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value
+  /// is not known.
+  static unsigned parse(const char *Value) {
+    return llvm::StringSwitch<SanitizeKind>(Value)
+#define SANITIZER(NAME, ID) .Case(NAME, ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
+#include "clang/Basic/Sanitizers.def"
+      .Default(SanitizeKind());
+  }
+
+  /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+  /// invalid components.
+  static unsigned parse(const Driver &D, const Arg *A) {
+    unsigned Kind = 0;
+    for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+      if (unsigned K = parse(A->getValue(I)))
+        Kind |= K;
+      else
+        D.Diag(diag::err_drv_unsupported_option_argument)
+          << A->getOption().getName() << A->getValue(I);
+    }
+    return Kind;
+  }
+
+  void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+    if (Kind & Address)
+      CmdArgs.push_back("-faddress-sanitizer");
+    if (Kind & Thread)
+      CmdArgs.push_back("-fthread-sanitizer");
+    if (Kind & Undefined)
+      CmdArgs.push_back("-fcatch-undefined-behavior");
+    if (!Kind)
+      return;
+    llvm::SmallString<256> SanitizeOpt("-fsanitize=");
+#define SANITIZER(NAME, ID) \
+    if (Kind & ID) \
+      SanitizeOpt += NAME ",";
+#include "clang/Basic/Sanitizers.def"
+    SanitizeOpt.pop_back();
+    CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
+  }
+};
+}
+
+/// Produce an argument string from argument \p A, which shows how it provides a
+/// value in \p Mask. For instance, the argument "-fsanitize=address,alignment"
+/// with mask \c NeedsUbsanRt would produce "-fsanitize=alignment".
+static std::string describeSanitizeArg(const Arg *A, unsigned Mask) {
+  if (!A->getOption().matches(options::OPT_fsanitize_EQ))
+    return A->getOption().getName();
+
+  for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
+    if (SanitizerArgs::parse(A->getValue(I)) & Mask)
+      return std::string("-fsanitize=") + A->getValue(I);
+
+  llvm_unreachable("arg didn't provide expected value");
+}
+
+/// Parse the sanitizer arguments from an argument list.
+static SanitizerArgs getSanitizerArgs(const Driver &D, const ArgList &Args) {
+  SanitizerArgs Sanitize;
+
+  const Arg *AsanArg, *TsanArg, *UbsanArg;
+
+  for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
+    unsigned Add = 0, Remove = 0;
+    if ((*I)->getOption().matches(options::OPT_faddress_sanitizer))
+      Add = SanitizerArgs::Address;
+    else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer))
+      Remove = SanitizerArgs::Address;
+    else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer))
+      Add = SanitizerArgs::Thread;
+    else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer))
+      Remove = SanitizerArgs::Thread;
+    else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior))
+      Add = SanitizerArgs::Undefined;
+    else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ))
+      Add = SanitizerArgs::parse(D, *I);
+    else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ))
+      Remove = SanitizerArgs::parse(D, *I);
+    else
+      continue;
+
+    (*I)->claim();
+
+    Sanitize.Kind |= Add;
+    Sanitize.Kind &= ~Remove;
+
+    if (Add & SanitizerArgs::NeedsAsanRt) AsanArg = *I;
+    if (Add & SanitizerArgs::NeedsTsanRt) TsanArg = *I;
+    if (Add & SanitizerArgs::NeedsUbsanRt) UbsanArg = *I;
+  }
+
+  // Only one runtime library can be used at once.
+  // FIXME: Allow Ubsan to be combined with the other two.
+  bool NeedsAsan = Sanitize.needsAsanRt();
+  bool NeedsTsan = Sanitize.needsTsanRt();
+  bool NeedsUbsan = Sanitize.needsUbsanRt();
+  if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
+    D.Diag(diag::err_drv_argument_not_allowed_with)
+      << describeSanitizeArg(NeedsAsan ? AsanArg : TsanArg,
+                             NeedsAsan ? SanitizerArgs::NeedsAsanRt
+                                       : SanitizerArgs::NeedsTsanRt)
+      << describeSanitizeArg(NeedsUbsan ? UbsanArg : TsanArg,
+                             NeedsUbsan ? SanitizerArgs::NeedsUbsanRt
+                                        : SanitizerArgs::NeedsTsanRt);
+
+  return Sanitize;
+}
+
 /// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
-  if (!Args.hasFlag(options::OPT_faddress_sanitizer,
-                    options::OPT_fno_address_sanitizer, false))
-    return;
   if(TC.getTriple().getEnvironment() == llvm::Triple::Android) {
     if (!Args.hasArg(options::OPT_shared)) {
       if (!Args.hasArg(options::OPT_pie))
@@ -1490,9 +1626,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
-  if (!Args.hasFlag(options::OPT_fthread_sanitizer,
-                    options::OPT_fno_thread_sanitizer, false))
-    return;
   if (!Args.hasArg(options::OPT_shared)) {
     // LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library
     // resource directory.
@@ -1511,8 +1644,6 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
 /// (Linux).
 static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
                             ArgStringList &CmdArgs) {
-  if (!Args.hasArg(options::OPT_fcatch_undefined_behavior))
-    return;
   if (!Args.hasArg(options::OPT_shared)) {
     // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library
     // resource directory.
@@ -2370,7 +2501,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("-ffreestanding");
 
   // Forward -f (flag) options which we can pass directly.
-  Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
   Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
   Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
   Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
@@ -2380,6 +2510,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
   Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
 
+  SanitizerArgs Sanitize = getSanitizerArgs(D, Args);
+  Sanitize.addArgs(Args, CmdArgs);
+
   // Report and error for -faltivec on anything other then PowerPC.
   if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
     if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
@@ -2390,14 +2523,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (getToolChain().SupportsProfiling())
     Args.AddLastArg(CmdArgs, options::OPT_pg);
 
-  if (Args.hasFlag(options::OPT_faddress_sanitizer,
-                   options::OPT_fno_address_sanitizer, false))
-    CmdArgs.push_back("-faddress-sanitizer");
-
-  if (Args.hasFlag(options::OPT_fthread_sanitizer,
-                   options::OPT_fno_thread_sanitizer, false))
-    CmdArgs.push_back("-fthread-sanitizer");
-
   // -flax-vector-conversions is default.
   if (!Args.hasFlag(options::OPT_flax_vector_conversions,
                     options::OPT_fno_lax_vector_conversions))
@@ -2544,9 +2669,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   // -frtti is default.
   if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) ||
-      KernelOrKext)
+      KernelOrKext) {
     CmdArgs.push_back("-fno-rtti");
 
+    // -fno-rtti cannot usefully be combined with -fsanitize=vptr.
+    if (Sanitize.Kind & SanitizerArgs::Vptr) {
+      llvm::StringRef NoRttiArg =
+        Args.getLastArg(options::OPT_mkernel,
+                        options::OPT_fapple_kext,
+                        options::OPT_fno_rtti)->getOption().getName();
+      D.Diag(diag::err_drv_argument_not_allowed_with)
+        << "-fsanitize=vptr" << NoRttiArg;
+    }
+  }
+
   // -fshort-enums=0 is default for all architectures except Hexagon.
   if (Args.hasFlag(options::OPT_fshort_enums,
                    options::OPT_fno_short_enums,
@@ -5972,8 +6108,11 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
 
+  SanitizerArgs Sanitize = getSanitizerArgs(D, Args);
+
   // Call this before we add the C++ ABI library.
-  addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+  if (Sanitize.needsUbsanRt())
+    addUbsanRTLinux(getToolChain(), Args, CmdArgs);
 
   if (D.CCCIsCXX &&
       !Args.hasArg(options::OPT_nostdlib) &&
@@ -5989,8 +6128,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
   }
 
   // Call this before we add the C run-time.
-  addAsanRTLinux(getToolChain(), Args, CmdArgs);
-  addTsanRTLinux(getToolChain(), Args, CmdArgs);
+  if (Sanitize.needsAsanRt())
+    addAsanRTLinux(getToolChain(), Args, CmdArgs);
+  if (Sanitize.needsTsanRt())
+    addTsanRTLinux(getToolChain(), Args, CmdArgs);
 
   if (!Args.hasArg(options::OPT_nostdlib)) {
     if (!Args.hasArg(options::OPT_nodefaultlibs)) {
index 703b9e7ff229b9beed813c3a1a2f867a1ce426cf..8cce72c5ead873a6506b3026a08aeb8aebf53670 100644 (file)
@@ -1273,6 +1273,37 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   case 1: Opts.setStackProtector(LangOptions::SSPOn);  break;
   case 2: Opts.setStackProtector(LangOptions::SSPReq); break;
   }
+
+  // Parse -fsanitize= arguments.
+  std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ);
+  for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) {
+    // Since the Opts.Sanitize* values are bitfields, it's a little tricky to
+    // efficiently map string values to them. Perform the mapping indirectly:
+    // convert strings to enumerated values, then switch over the enum to set
+    // the right bitfield value.
+    enum Sanitizer {
+#define SANITIZER(NAME, ID) \
+      ID,
+#include "clang/Basic/Sanitizers.def"
+      Unknown
+    };
+    switch (llvm::StringSwitch<unsigned>(Sanitizers[I])
+#define SANITIZER(NAME, ID) \
+              .Case(NAME, ID)
+#include "clang/Basic/Sanitizers.def"
+              .Default(Unknown)) {
+#define SANITIZER(NAME, ID) \
+    case ID: \
+      Opts.Sanitize##ID = true; \
+      break;
+#include "clang/Basic/Sanitizers.def"
+
+    case Unknown:
+      Diags.Report(diag::err_drv_invalid_value)
+        << "-fsanitize=" << Sanitizers[I];
+      break;
+    }
+  }
 }
 
 static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
index bfb30dc9a2c082e45a0cecd6d8d3aec196ecdd1b..59dbda15c88d0f70983bc7ce1ed2402678d031e7 100644 (file)
@@ -4,6 +4,12 @@
 // RUN:     -target i386-unknown-linux -faddress-sanitizer \
 // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
 // RUN:   | FileCheck --check-prefix=CHECK-LINUX %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target i386-unknown-linux -fsanitize=address \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-LINUX %s
+//
 // CHECK-LINUX: "{{.*}}ld{{(.exe)?}}"
 // CHECK-LINUX-NOT: "-lc"
 // CHECK-LINUX: libclang_rt.asan-i386.a"
 // RUN:     -target arm-linux-androideabi -faddress-sanitizer \
 // RUN:     --sysroot=%S/Inputs/basic_android_tree/sysroot \
 // RUN:   | FileCheck --check-prefix=CHECK-ANDROID %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi -fsanitize=address \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID %s
+//
 // CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}"
 // CHECK-ANDROID-NOT: "-lc"
 // CHECK-ANDROID: libclang_rt.asan-arm-android.so"
 // RUN:     --sysroot=%S/Inputs/basic_android_tree/sysroot \
 // RUN:     -shared \
 // RUN:   | FileCheck --check-prefix=CHECK-ANDROID-SHARED %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi -fsanitize=address \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN:     -shared \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID-SHARED %s
+//
 // CHECK-ANDROID-SHARED: "{{.*}}ld{{(.exe)?}}"
 // CHECK-ANDROID-SHARED-NOT: "-lc"
 // CHECK-ANDROID-SHARED: libclang_rt.asan-arm-android.so"
index 4c9a1b6c4423621aff10409c98286d13f0498748..c9b3796b44365863002b2aaab03bb4cee8192fbd 100644 (file)
@@ -2,6 +2,7 @@
 // RUN: %clang -O1 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
 // RUN: %clang -O2 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
 // RUN: %clang -O3 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang     -target i386-unknown-unknown -fsanitize=address  %s -S -emit-llvm -o - | FileCheck %s
 // Verify that -faddress-sanitizer invokes asan instrumentation.
 
 int foo(int *a) { return *a; }
index 42e81f872f8ac0897b5a855f334263a3a59f7e2f..7f325e097b383dcf88ccb91598b5f1baff6f1ad2 100644 (file)
@@ -1,5 +1,6 @@
 // Make sure AddressSanitizer disables _FORTIFY_SOURCE on Darwin.
 
 // RUN: %clang -faddress-sanitizer %s -E -dM -target x86_64-darwin - | FileCheck %s
+// RUN: %clang -fsanitize=address  %s -E -dM -target x86_64-darwin - | FileCheck %s
 
 // CHECK: #define _FORTIFY_SOURCE 0
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
new file mode 100644 (file)
index 0000000..047892a
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow),?){11}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -fno-sanitize=float-cast-overflow,vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size),?){9}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -c -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -c -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with 'fno-rtti'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,thread -fno-rtti %s -c -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANT
+// CHECK-SANA-SANT: '-fsanitize=address' not allowed with '-fsanitize=thread'
+
+// RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -c -o - 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
+// CHECK-ASAN-TSAN: 'faddress-sanitizer' not allowed with 'fthread-sanitizer'
index 1dadb8ea265b30c0b39a712a9432657861075de9..e454e4e78540798db8d816fae1b328f1e9117999 100644 (file)
@@ -2,6 +2,7 @@
 // RUN: %clang -O1 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
 // RUN: %clang -O2 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
 // RUN: %clang -O3 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang     -target i386-unknown-unknown -fsanitize=thread  %s -S -emit-llvm -o - | FileCheck %s
 // Verify that -fthread-sanitizer invokes tsan instrumentation.
 
 int foo(int *a) { return *a; }