[cfe-commits] [PATCH] Add three new sanitizers depending on ASan.

Alexey Samsonov samsonov at google.com
Thu Nov 29 12:15:45 PST 2012


  Added brief description of new sanitizer flags to UsersManual.
  Moved configuring AddressSanitizer passes (possible after
  r168910) to BackendUtil. There was a problem: extension
  callbacks we add to PassManagerBuilder are responsible for
  creating ASan passes, but can't take parameters (in our
  case we need LangOpts to determine which sanitizers are enabled).
  Use sneaky inheritance from PassManagerBuilder to resolve this
  (as suggested by Dan Gohman).

Hi kcc, rsmith,

http://llvm-reviews.chandlerc.com/D142

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D142?vs=362&id=371#toc

Files:
  lib/Driver/SanitizerArgs.h
  lib/Driver/Tools.cpp
  lib/CodeGen/BackendUtil.cpp
  test/Driver/fsanitize.c
  include/clang/Basic/Sanitizers.def
  docs/UsersManual.html

Index: lib/Driver/SanitizerArgs.h
===================================================================
--- lib/Driver/SanitizerArgs.h
+++ lib/Driver/SanitizerArgs.h
@@ -28,7 +28,7 @@
 #define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
 #define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
 #include "clang/Basic/Sanitizers.def"
-    NeedsAsanRt = Address,
+    NeedsAsanRt = AddressFull,
     NeedsTsanRt = Thread,
     NeedsUbsanRt = (Undefined & ~Bounds) | Integer
   };
@@ -44,7 +44,7 @@
   bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
 
   bool sanitizesVptr() const { return Kind & Vptr; }
-  
+
   void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
     if (!Kind)
       return;
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -1474,6 +1474,13 @@
     D.Diag(diag::err_drv_argument_not_allowed_with)
       << lastArgumentForKind(D, Args, NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
       << lastArgumentForKind(D, Args, NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
+
+  // If -fsanitize contains extra features of ASan, it should also
+  // explicitly contain -fsanitize=address.
+  if (NeedsAsan && ((Kind & Address) == 0))
+    D.Diag(diag::err_drv_argument_only_allowed_with)
+      << lastArgumentForKind(D, Args, NeedsAsanRt)
+      << "-fsanitize=address";
 }
 
 /// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
Index: lib/CodeGen/BackendUtil.cpp
===================================================================
--- lib/CodeGen/BackendUtil.cpp
+++ lib/CodeGen/BackendUtil.cpp
@@ -135,6 +135,17 @@
   void EmitAssembly(BackendAction Action, raw_ostream *OS);
 };
 
+// We need this wrapper to access LangOpts from extension functions that
+// we add to the PassManagerBuilder.
+class PassManagerBuilderWrapper : public PassManagerBuilder {
+ public:
+  PassManagerBuilderWrapper(const LangOptions &LangOpts)
+      : PassManagerBuilder(), LangOpts(LangOpts) {}
+  const LangOptions &getLangOpts() const { return LangOpts; }
+ private:
+  const LangOptions &LangOpts;
+};
+
 }
 
 static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
@@ -157,10 +168,16 @@
   PM.add(createBoundsCheckingPass());
 }
 
-static void addAddressSanitizerPass(const PassManagerBuilder &Builder,
-                                    PassManagerBase &PM) {
-  PM.add(createAddressSanitizerFunctionPass());
-  PM.add(createAddressSanitizerModulePass());
+static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
+                                      PassManagerBase &PM) {
+  const PassManagerBuilderWrapper *BuilderWrapper =
+      static_cast<const PassManagerBuilderWrapper*>(&Builder);
+  assert(BuilderWrapper);
+  const LangOptions &LangOpts = BuilderWrapper->getLangOpts();
+  PM.add(createAddressSanitizerFunctionPass(LangOpts.SanitizeInitOrder,
+                                            LangOpts.SanitizeUseAfterReturn,
+                                            LangOpts.SanitizeUseAfterScope));
+  PM.add(createAddressSanitizerModulePass(LangOpts.SanitizeInitOrder));
 }
 
 static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
@@ -179,7 +196,7 @@
     Inlining = CodeGenOpts.NoInlining;
   }
   
-  PassManagerBuilder PMBuilder;
+  PassManagerBuilderWrapper PMBuilder(LangOpts);
   PMBuilder.OptLevel = OptLevel;
   PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
 
@@ -206,9 +223,9 @@
 
   if (LangOpts.SanitizeAddress) {
     PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
-                           addAddressSanitizerPass);
+                           addAddressSanitizerPasses);
     PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
-                           addAddressSanitizerPass);
+                           addAddressSanitizerPasses);
   }
 
   if (LangOpts.SanitizeThread) {
Index: test/Driver/fsanitize.c
===================================================================
--- test/Driver/fsanitize.c
+++ test/Driver/fsanitize.c
@@ -10,6 +10,9 @@
 // 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|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|bounds),?){11}"}}
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address-full %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FULL
+// CHECK-ASAN-FULL: "-fsanitize={{((address|init-order|use-after-return|use-after-scope),?){4}"}}
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
 // CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with '-fno-rtti'
@@ -20,6 +23,9 @@
 // RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
 // CHECK-ASAN-TSAN: '-faddress-sanitizer' not allowed with '-fthread-sanitizer'
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=init-order %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-EXTRA-ASAN
+// CHECK-ONLY-EXTRA-ASAN: argument '-fsanitize=init-order' only allowed with '-fsanitize=address'
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize=alignment -fsanitize=vptr -fno-sanitize=vptr %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-ASAN
 // CHECK-UBSAN-ASAN: '-fsanitize=address' not allowed with '-fsanitize=alignment'
 
Index: include/clang/Basic/Sanitizers.def
===================================================================
--- include/clang/Basic/Sanitizers.def
+++ include/clang/Basic/Sanitizers.def
@@ -40,6 +40,13 @@
 
 // AddressSanitizer
 SANITIZER("address", Address)
+// More features of AddressSanitizer that should be turned on explicitly.
+SANITIZER("init-order", InitOrder)
+SANITIZER("use-after-return", UseAfterReturn)
+SANITIZER("use-after-scope", UseAfterScope)
+
+SANITIZER_GROUP("address-full", AddressFull,
+                Address | InitOrder | UseAfterReturn | UseAfterScope)
 
 // ThreadSanitizer
 SANITIZER("thread", Thread)
Index: docs/UsersManual.html
===================================================================
--- docs/UsersManual.html
+++ docs/UsersManual.html
@@ -886,6 +886,8 @@
 <li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
     <a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
     detector.</li>
+<li id="opt_fsanitize_address_full"><tt>-fsanitize=address-full</tt>:
+    AddressSanitizer with all the experimental features listed below.
 <li id="opt_fsanitize_integer"><tt>-fsanitize=integer</tt>:
     Enables checks for undefined or suspicious integer behavior.</li>
 <li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
@@ -898,7 +900,7 @@
     integer overflow.</li>
 </ul>
 
-The following more fine-grained checks are also available:
+The following more fine-grained undefined behavior checks are available:
 
 <ul>
 <li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
@@ -941,6 +943,20 @@
     <tt>-fno-rtti</tt>.</li>
 </ul>
 
+Experimental features of AddressSanitizer (not ready for widespread use,
+require explicit <tt>-fsanitize=address</tt>):
+
+<ul>
+<li id="opt_fsanitize_init_order"><tt>-fsanitize=init-order</tt>:
+Check for dynamic initialization order problems.</li>
+<li id="opt_fsanitize_use_after_return"><tt>-fsanitize=use-after-return</tt>:
+Check for use-after-return errors (accessing local variable after the function
+exit).
+<li id="opt_fsanitize_use_after_scope"><tt>-fsanitize=use-after-scope</tt>:
+Check for use-after-scope errors (accesing local variable after it went out of
+scope).
+</ul>
+
 The <tt>-fsanitize=</tt> argument must also be provided when linking, in order
 to link to the appropriate runtime library. It is not possible to combine the
 <tt>-fsanitize=address</tt> and <tt>-fsanitize=thread</tt> checkers in the same
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D142.2.patch
Type: text/x-patch
Size: 8307 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20121129/aa3ffed5/attachment.bin>


More information about the cfe-commits mailing list