From: Alexey Samsonov Date: Thu, 29 Nov 2012 22:36:21 +0000 (+0000) Subject: This patch exposes to Clang users three more sanitizers are experimental features... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4d1a6e41e1eaeaf5a4672c802519f15c8fb91e91;p=clang This patch exposes to Clang users three more sanitizers are experimental features of ASan: 1) init-order sanitizer: initialization-order checker. Status: usable, but may produce false positives w/o proper blacklisting. 2) use-after-return sanitizer Status: implemented, but heavily understed. Should be optional, as it significanlty slows program down. 3) use-after-scope sanitizer Status: in progress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168950 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 967d0dbf7b..e4f44044c2 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -886,6 +886,8 @@ main checks are:
  • -fsanitize=address: AddressSanitizer, a memory error detector.
  • +
  • -fsanitize=address-full: + AddressSanitizer with all the experimental features listed below.
  • -fsanitize=integer: Enables checks for undefined or suspicious integer behavior.
  • -fsanitize=thread: @@ -941,6 +943,20 @@ The following more fine-grained checks are also available: -fno-rtti.
  • +Experimental features of AddressSanitizer (not ready for widespread use, +require explicit -fsanitize=address): + + + The -fsanitize= argument must also be provided when linking, in order to link to the appropriate runtime library. It is not possible to combine the -fsanitize=address and -fsanitize=thread checkers in the same diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def index 1085392911..5b6df6f2c1 100644 --- a/include/clang/Basic/Sanitizers.def +++ b/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) diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index d54ed2225a..a5cc2ea004 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -135,6 +135,17 @@ public: 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,15 @@ static void addBoundsCheckingPass(const PassManagerBuilder &Builder, 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(Builder); + 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, @@ -178,8 +194,8 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) { OptLevel = 0; Inlining = CodeGenOpts.NoInlining; } - - PassManagerBuilder PMBuilder; + + PassManagerBuilderWrapper PMBuilder(LangOpts); PMBuilder.OptLevel = OptLevel; PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize; @@ -206,9 +222,9 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) { if (LangOpts.SanitizeAddress) { PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, - addAddressSanitizerPass); + addAddressSanitizerPasses); PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, - addAddressSanitizerPass); + addAddressSanitizerPasses); } if (LangOpts.SanitizeThread) { diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h index 52a6c2ec4b..af92fa070c 100644 --- a/lib/Driver/SanitizerArgs.h +++ b/lib/Driver/SanitizerArgs.h @@ -28,7 +28,7 @@ class SanitizerArgs { #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 @@ class SanitizerArgs { bool needsUbsanRt() const { return Kind & NeedsUbsanRt; } bool sanitizesVptr() const { return Kind & Vptr; } - + void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Kind) return; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index f9cb5eff53..f2c1a03caf 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1474,6 +1474,13 @@ SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) { 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). diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c index a7c947716a..1e2485b8d8 100644 --- a/test/Driver/fsanitize.c +++ b/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'