[clang] 96c6349 - [hwasan] Use stack safety analysis.

Vitaly Buka via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 22 16:20:40 PDT 2021


Author: Florian Mayer
Date: 2021-07-22T16:20:27-07:00
New Revision: 96c63492cb952431fd9732146663fe227f8c52c1

URL: https://github.com/llvm/llvm-project/commit/96c63492cb952431fd9732146663fe227f8c52c1
DIFF: https://github.com/llvm/llvm-project/commit/96c63492cb952431fd9732146663fe227f8c52c1.diff

LOG: [hwasan] Use stack safety analysis.

This avoids unnecessary instrumentation.

Reviewed By: eugenis, vitalybuka

Differential Revision: https://reviews.llvm.org/D105703

Added: 
    clang/test/CodeGen/hwasan-stack-safety-analysis.c
    llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll

Modified: 
    clang/lib/CodeGen/BackendUtil.cpp
    llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h
    llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 9aa67ed2a67ba..481f5347d978b 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -314,14 +314,19 @@ static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
       static_cast<const PassManagerBuilderWrapper &>(Builder);
   const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
   bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
-  PM.add(
-      createHWAddressSanitizerLegacyPassPass(/*CompileKernel*/ false, Recover));
+  PM.add(createHWAddressSanitizerLegacyPassPass(
+      /*CompileKernel*/ false, Recover,
+      /*DisableOptimization*/ CGOpts.OptimizationLevel == 0));
 }
 
 static void addKernelHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
-                                            legacy::PassManagerBase &PM) {
+                                              legacy::PassManagerBase &PM) {
+  const PassManagerBuilderWrapper &BuilderWrapper =
+      static_cast<const PassManagerBuilderWrapper &>(Builder);
+  const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
   PM.add(createHWAddressSanitizerLegacyPassPass(
-      /*CompileKernel*/ true, /*Recover*/ true));
+      /*CompileKernel*/ true, /*Recover*/ true,
+      /*DisableOptimization*/ CGOpts.OptimizationLevel == 0));
 }
 
 static void addGeneralOptsForMemorySanitizer(const PassManagerBuilder &Builder,
@@ -1164,7 +1169,9 @@ static void addSanitizers(const Triple &TargetTriple,
     auto HWASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
       if (LangOpts.Sanitize.has(Mask)) {
         bool Recover = CodeGenOpts.SanitizeRecover.has(Mask);
-        MPM.addPass(HWAddressSanitizerPass(CompileKernel, Recover));
+        MPM.addPass(HWAddressSanitizerPass(
+            CompileKernel, Recover,
+            /*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0));
       }
     };
     HWASanPass(SanitizerKind::HWAddress, false);

diff  --git a/clang/test/CodeGen/hwasan-stack-safety-analysis.c b/clang/test/CodeGen/hwasan-stack-safety-analysis.c
new file mode 100644
index 0000000000000..5c4f34027bacd
--- /dev/null
+++ b/clang/test/CodeGen/hwasan-stack-safety-analysis.c
@@ -0,0 +1,15 @@
+// RUN: %clang -fsanitize=hwaddress -target aarch64-linux-gnu -S -emit-llvm -mllvm -hwasan-use-stack-safety=true -mllvm -hwasan-generate-tags-with-calls -O2 %s -o - | FileCheck %s --check-prefix=SAFETY
+// RUN: %clang -fsanitize=hwaddress -target aarch64-linux-gnu -S -emit-llvm -mllvm -hwasan-use-stack-safety=false -mllvm -hwasan-generate-tags-with-calls -O2 %s -o - | FileCheck %s --check-prefix=NOSAFETY
+
+// Default when optimizing, but not with O0.
+// RUN: %clang -fsanitize=hwaddress -target aarch64-linux-gnu -S -emit-llvm -mllvm -hwasan-generate-tags-with-calls -O2 %s -o - | FileCheck %s --check-prefix=SAFETY
+// RUN: %clang -fsanitize=hwaddress -target aarch64-linux-gnu -S -emit-llvm -mllvm -hwasan-generate-tags-with-calls -O0 %s -o - | FileCheck %s --check-prefix=NOSAFETY
+
+int main(int argc, char **argv) {
+  char buf[10];
+  volatile char *x = buf;
+  *x = 0;
+  return buf[0];
+  // NOSAFETY: __hwasan_generate_tag
+  // SAFETY-NOT: __hwasan_generate_tag
+}

diff  --git a/llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h
index 76e02f06435c3..2e4f3338030a4 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h
@@ -25,17 +25,21 @@ namespace llvm {
 class HWAddressSanitizerPass : public PassInfoMixin<HWAddressSanitizerPass> {
 public:
   explicit HWAddressSanitizerPass(bool CompileKernel = false,
-                                  bool Recover = false);
+                                  bool Recover = false,
+                                  bool DisableOptimization = false);
   PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
   static bool isRequired() { return true; }
 
 private:
   bool CompileKernel;
   bool Recover;
+  bool DisableOptimization;
 };
 
-FunctionPass *createHWAddressSanitizerLegacyPassPass(bool CompileKernel = false,
-                                                     bool Recover = false);
+FunctionPass *
+createHWAddressSanitizerLegacyPassPass(bool CompileKernel = false,
+                                       bool Recover = false,
+                                       bool DisableOptimization = false);
 
 namespace HWASanAccessInfo {
 

diff  --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 7b674b09fd055..f800e500cc25b 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/StackSafetyAnalysis.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/BasicBlock.h"
@@ -109,6 +110,11 @@ static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
                                        cl::desc("instrument stack (allocas)"),
                                        cl::Hidden, cl::init(true));
 
+static cl::opt<bool>
+    ClUseStackSafety("hwasan-use-stack-safety", cl::Hidden, cl::init(true),
+                     cl::Hidden, cl::desc("Use Stack Safety analysis results"),
+                     cl::Optional);
+
 static cl::opt<bool> ClUARRetagToZero(
     "hwasan-uar-retag-to-zero",
     cl::desc("Clear alloca tags before returning from the function to allow "
@@ -204,11 +210,23 @@ bool shouldInstrumentWithCalls(const Triple &TargetTriple) {
   return ClInstrumentWithCalls || TargetTriple.getArch() == Triple::x86_64;
 }
 
+bool mightUseStackSafetyAnalysis(bool DisableOptimization) {
+  return ClUseStackSafety.getNumOccurrences() ? ClUseStackSafety
+                                              : !DisableOptimization;
+}
+
+bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,
+                                  bool DisableOptimization) {
+  return shouldInstrumentStack(TargetTriple) &&
+         mightUseStackSafetyAnalysis(DisableOptimization);
+}
 /// An instrumentation pass implementing detection of addressability bugs
 /// using tagged pointers.
 class HWAddressSanitizer {
 public:
-  HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover) : M(M) {
+  HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover,
+                     const StackSafetyGlobalInfo *SSI)
+      : M(M), SSI(SSI) {
     this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
     this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0
                               ? ClEnableKhwasan
@@ -217,6 +235,8 @@ class HWAddressSanitizer {
     initializeModule();
   }
 
+  void setSSI(const StackSafetyGlobalInfo *S) { SSI = S; }
+
   bool sanitizeFunction(Function &F);
   void initializeModule();
   void createHwasanCtorComdat();
@@ -269,6 +289,7 @@ class HWAddressSanitizer {
 private:
   LLVMContext *C;
   Module &M;
+  const StackSafetyGlobalInfo *SSI;
   Triple TargetTriple;
   FunctionCallee HWAsanMemmove, HWAsanMemcpy, HWAsanMemset;
   FunctionCallee HWAsanHandleVfork;
@@ -339,7 +360,8 @@ class HWAddressSanitizerLegacyPass : public FunctionPass {
   static char ID;
 
   explicit HWAddressSanitizerLegacyPass(bool CompileKernel = false,
-                                        bool Recover = false)
+                                        bool Recover = false,
+                                        bool DisableOptimization = false)
       : FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover) {
     initializeHWAddressSanitizerLegacyPassPass(
         *PassRegistry::getPassRegistry());
@@ -348,11 +370,19 @@ class HWAddressSanitizerLegacyPass : public FunctionPass {
   StringRef getPassName() const override { return "HWAddressSanitizer"; }
 
   bool doInitialization(Module &M) override {
-    HWASan = std::make_unique<HWAddressSanitizer>(M, CompileKernel, Recover);
+    HWASan = std::make_unique<HWAddressSanitizer>(M, CompileKernel, Recover,
+                                                  /*SSI=*/nullptr);
     return true;
   }
 
   bool runOnFunction(Function &F) override {
+    if (shouldUseStackSafetyAnalysis(Triple(F.getParent()->getTargetTriple()),
+                                     DisableOptimization)) {
+      // We cannot call getAnalysis in doInitialization, that would cause a
+      // crash as the required analyses are not initialized yet.
+      HWASan->setSSI(
+          &getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult());
+    }
     return HWASan->sanitizeFunction(F);
   }
 
@@ -361,10 +391,20 @@ class HWAddressSanitizerLegacyPass : public FunctionPass {
     return false;
   }
 
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    // This is an over-estimation of, in case we are building for an
+    // architecture that doesn't allow stack tagging we will still load the
+    // analysis.
+    // This is so we don't need to plumb TargetTriple all the way to here.
+    if (mightUseStackSafetyAnalysis(DisableOptimization))
+      AU.addRequired<StackSafetyGlobalInfoWrapperPass>();
+  }
+
 private:
   std::unique_ptr<HWAddressSanitizer> HWASan;
   bool CompileKernel;
   bool Recover;
+  bool DisableOptimization;
 };
 
 } // end anonymous namespace
@@ -375,23 +415,32 @@ INITIALIZE_PASS_BEGIN(
     HWAddressSanitizerLegacyPass, "hwasan",
     "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
     false)
+INITIALIZE_PASS_DEPENDENCY(StackSafetyGlobalInfoWrapperPass)
 INITIALIZE_PASS_END(
     HWAddressSanitizerLegacyPass, "hwasan",
     "HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
     false)
 
-FunctionPass *llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel,
-                                                           bool Recover) {
+FunctionPass *
+llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel, bool Recover,
+                                             bool DisableOptimization) {
   assert(!CompileKernel || Recover);
-  return new HWAddressSanitizerLegacyPass(CompileKernel, Recover);
+  return new HWAddressSanitizerLegacyPass(CompileKernel, Recover,
+                                          DisableOptimization);
 }
 
-HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover)
-    : CompileKernel(CompileKernel), Recover(Recover) {}
+HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover,
+                                               bool DisableOptimization)
+    : CompileKernel(CompileKernel), Recover(Recover),
+      DisableOptimization(DisableOptimization) {}
 
 PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
                                               ModuleAnalysisManager &MAM) {
-  HWAddressSanitizer HWASan(M, CompileKernel, Recover);
+  const StackSafetyGlobalInfo *SSI = nullptr;
+  if (shouldUseStackSafetyAnalysis(llvm::Triple(M.getTargetTriple()),
+                                   DisableOptimization))
+    SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
+  HWAddressSanitizer HWASan(M, CompileKernel, Recover, SSI);
   bool Modified = false;
   for (Function &F : M)
     Modified |= HWASan.sanitizeFunction(F);
@@ -1245,7 +1294,9 @@ bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
           // dynamic alloca instrumentation for them as well.
           !AI.isUsedWithInAlloca() &&
           // swifterror allocas are register promoted by ISel
-          !AI.isSwiftError());
+          !AI.isSwiftError()) &&
+         // safe allocas are not interesting
+         !(SSI && SSI->isSafe(AI));
 }
 
 bool HWAddressSanitizer::sanitizeFunction(Function &F) {

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll
new file mode 100644
index 0000000000000..766660a5c26f8
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll
@@ -0,0 +1,42 @@
+; RUN: opt -hwasan -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY
+; RUN: opt -hwasan -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux-gnu"
+
+; Check a safe alloca to ensure it does not get a tag.
+define i32 @test_load(i32* %a) sanitize_hwaddress {
+entry:
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  %buf.sroa.0 = alloca i8, align 4
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Check a non-safe alloca to ensure it gets a tag.
+define i32 @test_use(i32* %a) sanitize_hwaddress {
+entry:
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  %buf.sroa.0 = alloca i8, align 4
+  call void @use(i8* nonnull %buf.sroa.0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
+
+declare void @use(i8* nocapture)
+
+!8 = !{!9, !9, i64 0}
+!9 = !{!"omnipotent char", !10, i64 0}
+!10 = !{!"Simple C/C++ TBAA"}


        


More information about the cfe-commits mailing list