This revision was automatically updated to reflect the committed changes.
Closed by commit rL311186: [SanitizerCoverage] Add stack depth tracing 
instrumentation. (authored by morehouse).

Changed prior to commit:
  https://reviews.llvm.org/D36839?vs=111570&id=111718#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D36839

Files:
  cfe/trunk/include/clang/Driver/CC1Options.td
  cfe/trunk/include/clang/Frontend/CodeGenOptions.def
  cfe/trunk/lib/CodeGen/BackendUtil.cpp
  cfe/trunk/lib/Driver/SanitizerArgs.cpp
  cfe/trunk/lib/Frontend/CompilerInvocation.cpp
  cfe/trunk/test/Driver/fsanitize-coverage.c
  
compiler-rt/trunk/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc
  llvm/trunk/include/llvm/Transforms/Instrumentation.h
  llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
  llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
  llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
  llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll

Index: llvm/trunk/include/llvm/Transforms/Instrumentation.h
===================================================================
--- llvm/trunk/include/llvm/Transforms/Instrumentation.h
+++ llvm/trunk/include/llvm/Transforms/Instrumentation.h
@@ -185,6 +185,7 @@
   bool Inline8bitCounters = false;
   bool PCTable = false;
   bool NoPrune = false;
+  bool StackDepth = false;
 
   SanitizerCoverageOptions() = default;
 };
Index: llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll
===================================================================
--- llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll
+++ llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll
@@ -0,0 +1,50 @@
+; This check verifies that stack depth instrumentation works correctly.
+; RUN: opt < %s -sancov -sanitizer-coverage-level=1 \
+; RUN:     -sanitizer-coverage-stack-depth -S | FileCheck %s --enable-var-scope
+; RUN: opt < %s -sancov -sanitizer-coverage-level=3 \
+; RUN:     -sanitizer-coverage-stack-depth -sanitizer-coverage-trace-pc-guard \
+; RUN:     -S | FileCheck %s --enable-var-scope
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: @__sancov_lowest_stack = thread_local global i64 -1
+@__sancov_lowest_stack = thread_local global i64 0, align 8
+
+define i32 @foo() {
+entry:
+; CHECK-LABEL: define i32 @foo
+; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
+; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType:i[0-9]+]]
+; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
+; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
+; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
+; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
+; CHECK: <label>:[[ifLabel]]:
+; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
+; CHECK: ret i32 7
+
+  ret i32 7
+}
+
+define i32 @bar() {
+entry:
+; CHECK-LABEL: define i32 @bar
+; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
+; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType]]
+; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
+; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
+; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
+; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
+; CHECK: <label>:[[ifLabel]]:
+; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
+; CHECK: %call = call i32 @foo()
+; CHECK: ret i32 %call
+
+  %call = call i32 @foo()
+  ret i32 %call
+}
+
+define weak_odr hidden i64* @_ZTW21__sancov_lowest_stack() {
+  ret i64* @__sancov_lowest_stack
+}
Index: llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
===================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -17,12 +17,15 @@
 #include "llvm/Analysis/PostDominators.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/CallSite.h"
+#include "llvm/IR/Constant.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
@@ -73,6 +76,10 @@
 static const char *const SanCovCountersSectionName = "sancov_cntrs";
 static const char *const SanCovPCsSectionName = "sancov_pcs";
 
+static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
+static const char *const SanCovLowestStackTLSWrapperName =
+    "_ZTW21__sancov_lowest_stack";
+
 static cl::opt<int> ClCoverageLevel(
     "sanitizer-coverage-level",
     cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
@@ -119,6 +126,10 @@
                   cl::desc("Reduce the number of instrumented blocks"),
                   cl::Hidden, cl::init(true));
 
+static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth",
+                                  cl::desc("max stack depth tracing"),
+                                  cl::Hidden, cl::init(false));
+
 namespace {
 
 SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
@@ -156,9 +167,11 @@
   Options.TracePCGuard |= ClTracePCGuard;
   Options.Inline8bitCounters |= ClInline8bitCounters;
   Options.PCTable |= ClCreatePCTable;
-  if (!Options.TracePCGuard && !Options.TracePC && !Options.Inline8bitCounters)
-    Options.TracePCGuard = true; // TracePCGuard is default.
   Options.NoPrune |= !ClPruneBlocks;
+  Options.StackDepth |= ClStackDepth;
+  if (!Options.TracePCGuard && !Options.TracePC &&
+      !Options.Inline8bitCounters && !Options.StackDepth)
+    Options.TracePCGuard = true; // TracePCGuard is default.
   return Options;
 }
 
@@ -216,6 +229,8 @@
   Function *SanCovTraceDivFunction[2];
   Function *SanCovTraceGepFunction;
   Function *SanCovTraceSwitchFunction;
+  Function *SanCovLowestStackTLSWrapper;
+  GlobalVariable *SanCovLowestStack;
   InlineAsm *EmptyAsm;
   Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
       *Int16Ty, *Int8Ty, *Int8PtrTy;
@@ -333,6 +348,24 @@
   SanCovTraceSwitchFunction =
       checkSanitizerInterfaceFunction(M.getOrInsertFunction(
           SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy));
+
+  Constant *SanCovLowestStackConstant =
+      M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
+  SanCovLowestStackTLSWrapper =
+      checkSanitizerInterfaceFunction(M.getOrInsertFunction(
+          SanCovLowestStackTLSWrapperName, IntptrTy->getPointerTo()));
+  if (Options.StackDepth) {
+    assert(isa<GlobalVariable>(SanCovLowestStackConstant));
+    SanCovLowestStack = cast<GlobalVariable>(SanCovLowestStackConstant);
+    if (!SanCovLowestStack->isDeclaration()) {
+      // Check that the user has correctly defined:
+      //     thread_local uintptr_t __sancov_lowest_stack
+      // and initialize it.
+      assert(SanCovLowestStack->isThreadLocal());
+      SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
+    }
+  }
+
   // Make sure smaller parameters are zero-extended to i64 as required by the
   // x86_64 ABI.
   if (TargetTriple.getArch() == Triple::x86_64) {
@@ -451,6 +484,9 @@
   if (F.getName() == "__local_stdio_printf_options" ||
       F.getName() == "__local_stdio_scanf_options")
     return false;
+  // Avoid infinite recursion by not instrumenting stack depth TLS wrapper
+  if (F.getName() == SanCovLowestStackTLSWrapperName)
+    return false;
   // Don't instrument functions using SEH for now. Splitting basic blocks like
   // we do for coverage breaks WinEHPrepare.
   // FIXME: Remove this when SEH no longer uses landingpad pattern matching.
@@ -728,6 +764,20 @@
     SetNoSanitizeMetadata(Load);
     SetNoSanitizeMetadata(Store);
   }
+  if (Options.StackDepth && IsEntryBB) {
+    // Check stack depth.  If it's the deepest so far, record it.
+    Function *GetFrameAddr =
+        Intrinsic::getDeclaration(F.getParent(), Intrinsic::frameaddress);
+    auto FrameAddrPtr =
+        IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
+    auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
+    auto LowestStackPtr = IRB.CreateCall(SanCovLowestStackTLSWrapper);
+    auto LowestStack = IRB.CreateLoad(LowestStackPtr);
+    auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
+    auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
+    IRBuilder<> ThenIRB(ThenTerm);
+    ThenIRB.CreateStore(FrameAddrInt, LowestStackPtr);
+  }
 }
 
 std::string
Index: llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
===================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
@@ -120,19 +120,8 @@
     return PCs()[Idx];
   }
 
-  void RecordCurrentStack() {
-    uintptr_t Stack = GetCurrentStack();
-    if (Stack < LowestStack)
-      LowestStack = Stack;
-  }
-  void RecordInitialStack() {
-    InitialStack = GetCurrentStack();
-    LowestStack = InitialStack;
-  }
-  uintptr_t GetCurrentStack() const {
-    return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
-  }
-  uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; }
+  void RecordInitialStack();
+  uintptr_t GetMaxStackOffset() const;
 
   template<class CallBack>
   void ForEachObservedPC(CallBack CB) {
@@ -167,7 +156,7 @@
   std::set<uintptr_t> ObservedPCs;
 
   ValueBitMap ValueProfileMap;
-  uintptr_t InitialStack, LowestStack;  // Assume stack grows down.
+  uintptr_t InitialStack;
 };
 
 template <class Callback>
Index: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
===================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
@@ -31,6 +31,9 @@
 ATTRIBUTE_INTERFACE
 uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
 
+// Used by -fsanitize-coverage=stack-depth to track stack depth
+ATTRIBUTE_INTERFACE thread_local uintptr_t __sancov_lowest_stack;
+
 namespace fuzzer {
 
 TracePC TPC;
@@ -340,6 +343,14 @@
   }
 }
 
+void TracePC::RecordInitialStack() {
+  InitialStack = __sancov_lowest_stack;
+}
+
+uintptr_t TracePC::GetMaxStackOffset() const {
+  return InitialStack - __sancov_lowest_stack;  // Stack grows down
+}
+
 } // namespace fuzzer
 
 extern "C" {
@@ -350,8 +361,6 @@
   uint32_t Idx = *Guard;
   __sancov_trace_pc_pcs[Idx] = PC;
   __sancov_trace_pc_guard_8bit_counters[Idx]++;
-  // Uncomment the following line to get stack-depth profiling.
-  // fuzzer::TPC.RecordCurrentStack();
 }
 
 // Best-effort support for -fsanitize-coverage=trace-pc, which is available
Index: cfe/trunk/lib/CodeGen/BackendUtil.cpp
===================================================================
--- cfe/trunk/lib/CodeGen/BackendUtil.cpp
+++ cfe/trunk/lib/CodeGen/BackendUtil.cpp
@@ -190,6 +190,7 @@
   Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune;
   Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
   Opts.PCTable = CGOpts.SanitizeCoveragePCTable;
+  Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
   PM.add(createSanitizerCoverageModulePass(Opts));
 }
 
Index: cfe/trunk/lib/Driver/SanitizerArgs.cpp
===================================================================
--- cfe/trunk/lib/Driver/SanitizerArgs.cpp
+++ cfe/trunk/lib/Driver/SanitizerArgs.cpp
@@ -58,6 +58,7 @@
   CoverageNoPrune = 1 << 11,
   CoverageInline8bitCounters = 1 << 12,
   CoveragePCTable = 1 << 13,
+  CoverageStackDepth = 1 << 14,
 };
 
 /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -556,10 +557,14 @@
   }
 
   // trace-pc w/o func/bb/edge implies edge.
-  if ((CoverageFeatures &
-       (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) &&
-      !(CoverageFeatures & InsertionPointTypes))
-    CoverageFeatures |= CoverageEdge;
+  if (!(CoverageFeatures & InsertionPointTypes)) {
+    if (CoverageFeatures &
+        (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters))
+      CoverageFeatures |= CoverageEdge;
+
+    if (CoverageFeatures & CoverageStackDepth)
+      CoverageFeatures |= CoverageFunc;
+  }
 
   if (AllAddedKinds & Address) {
     AsanSharedRuntime =
@@ -672,7 +677,8 @@
     std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"),
     std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"),
     std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"),
-    std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune")};
+    std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
+    std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")};
   for (auto F : CoverageFlags) {
     if (CoverageFeatures & F.first)
       CmdArgs.push_back(F.second);
@@ -835,6 +841,7 @@
         .Case("no-prune", CoverageNoPrune)
         .Case("inline-8bit-counters", CoverageInline8bitCounters)
         .Case("pc-table", CoveragePCTable)
+        .Case("stack-depth", CoverageStackDepth)
         .Default(0);
     if (F == 0)
       D.Diag(clang::diag::err_drv_unsupported_option_argument)
Index: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp
@@ -795,6 +795,8 @@
   Opts.SanitizeCoverageInline8bitCounters =
       Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters);
   Opts.SanitizeCoveragePCTable = Args.hasArg(OPT_fsanitize_coverage_pc_table);
+  Opts.SanitizeCoverageStackDepth =
+      Args.hasArg(OPT_fsanitize_coverage_stack_depth);
   Opts.SanitizeMemoryTrackOrigins =
       getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
   Opts.SanitizeMemoryUseAfterDtor =
Index: cfe/trunk/include/clang/Driver/CC1Options.td
===================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td
+++ cfe/trunk/include/clang/Driver/CC1Options.td
@@ -307,6 +307,9 @@
 def fsanitize_coverage_no_prune
     : Flag<["-"], "fsanitize-coverage-no-prune">,
       HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">;
+def fsanitize_coverage_stack_depth
+    : Flag<["-"], "fsanitize-coverage-stack-depth">,
+      HelpText<"Enable max stack depth tracing">;
 def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
     HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, "
              "or none">, Values<"none,clang,llvm">;
Index: cfe/trunk/include/clang/Frontend/CodeGenOptions.def
===================================================================
--- cfe/trunk/include/clang/Frontend/CodeGenOptions.def
+++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def
@@ -169,6 +169,7 @@
 CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters.
 CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table.
 CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning.
+CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing
 CODEGENOPT(SanitizeStats     , 1, 0) ///< Collect statistics for sanitizers.
 CODEGENOPT(SimplifyLibCalls  , 1, 1) ///< Set when -fbuiltin is enabled.
 CODEGENOPT(SoftFloat         , 1, 0) ///< -soft-float.
Index: cfe/trunk/test/Driver/fsanitize-coverage.c
===================================================================
--- cfe/trunk/test/Driver/fsanitize-coverage.c
+++ cfe/trunk/test/Driver/fsanitize-coverage.c
@@ -72,6 +72,17 @@
 // CHECK-TRACE_PC_GUARD_FUNC: -fsanitize-coverage-type=1
 // CHECK-TRACE_PC_GUARD_FUNC: -fsanitize-coverage-trace-pc-guard
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=stack-depth %s \
+// RUN:     -### 2>&1 | FileCheck %s --check-prefix=CHECK-STACK-DEPTH
+// RUN: %clang -target x86_64-linux-gnu \
+// RUN:     -fsanitize-coverage=trace-pc-guard,stack-depth %s -### 2>&1 | \
+// RUN:     FileCheck %s --check-prefix=CHECK-STACK-DEPTH-PC-GUARD
+// CHECK-STACK-DEPTH: -fsanitize-coverage-type=1
+// CHECK-STACK-DEPTH: -fsanitize-coverage-stack-depth
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-type=3
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-trace-pc-guard
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-stack-depth
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=trace-cmp,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TYPE-NECESSARY
 // CHECK-NO-TYPE-NECESSARY-NOT: error:
 // CHECK-NO-TYPE-NECESSARY: -fsanitize-coverage-indirect-calls
Index: compiler-rt/trunk/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc
===================================================================
--- compiler-rt/trunk/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc
+++ compiler-rt/trunk/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc
@@ -0,0 +1,32 @@
+// Tests -fsanitize-coverage=stack-depth
+//
+// XFAIL: tsan
+//
+// RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=stack-depth %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not Assertion{{.*}}failed
+// RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=trace-pc-guard,stack-depth \
+// RUN:     %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not Assertion{{.*}}failed
+
+#include <cstdint>
+#include <cstdio>
+#include <cassert>
+
+thread_local uintptr_t __sancov_lowest_stack;
+uintptr_t last_stack;
+
+void foo(int recurse) {
+  assert(__sancov_lowest_stack < last_stack);
+  last_stack = __sancov_lowest_stack;
+  if (recurse <= 0) return;
+  foo(recurse - 1);
+}
+
+int main() {
+  last_stack = __sancov_lowest_stack;
+  foo(100);
+  printf("Success!\n");
+  return 0;
+}
+
+// CHECK: Success!
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to