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.

llvm-svn: 167411

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

index 7bce573..fab4a54 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/clang/include/clang/Basic/Sanitizers.def b/clang/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 3c39eb6..ba609fa 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 05487c4..d1109ff 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 703b9e7..8cce72c 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 bfb30dc..59dbda1 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 4c9a1b6..c9b3796 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 42e81f8..7f325e0 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/clang/test/Driver/fsanitize.c b/clang/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 1dadb8e..e454e4e 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; }