[llvm] r311186 - [SanitizerCoverage] Add stack depth tracing instrumentation.

Matt Morehouse via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 18 11:43:30 PDT 2017


Author: morehouse
Date: Fri Aug 18 11:43:30 2017
New Revision: 311186

URL: http://llvm.org/viewvc/llvm-project?rev=311186&view=rev
Log:
[SanitizerCoverage] Add stack depth tracing instrumentation.

Summary:
Augment SanitizerCoverage to insert maximum stack depth tracing for
use by libFuzzer.  The new instrumentation is enabled by the flag
-fsanitize-coverage=stack-depth and is compatible with the existing
trace-pc-guard coverage.  The user must also declare the following
global variable in their code:
  thread_local uintptr_t __sancov_lowest_stack

https://bugs.llvm.org/show_bug.cgi?id=33857

Reviewers: vitalybuka, kcc

Reviewed By: vitalybuka

Subscribers: kubamracek, hiraditya, cfe-commits, llvm-commits

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

Added:
    llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll
Modified:
    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

Modified: llvm/trunk/include/llvm/Transforms/Instrumentation.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Instrumentation.h?rev=311186&r1=311185&r2=311186&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Instrumentation.h (original)
+++ llvm/trunk/include/llvm/Transforms/Instrumentation.h Fri Aug 18 11:43:30 2017
@@ -185,6 +185,7 @@ struct SanitizerCoverageOptions {
   bool Inline8bitCounters = false;
   bool PCTable = false;
   bool NoPrune = false;
+  bool StackDepth = false;
 
   SanitizerCoverageOptions() = default;
 };

Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp?rev=311186&r1=311185&r2=311186&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp Fri Aug 18 11:43:30 2017
@@ -31,6 +31,9 @@ uint8_t __sancov_trace_pc_guard_8bit_cou
 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::ClearInlineCounters() {
   }
 }
 
+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 @@ void __sanitizer_cov_trace_pc_guard(uint
   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

Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.h?rev=311186&r1=311185&r2=311186&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.h Fri Aug 18 11:43:30 2017
@@ -120,19 +120,8 @@ class TracePC {
     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 @@ private:
   std::set<uintptr_t> ObservedPCs;
 
   ValueBitMap ValueProfileMap;
-  uintptr_t InitialStack, LowestStack;  // Assume stack grows down.
+  uintptr_t InitialStack;
 };
 
 template <class Callback>

Modified: llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp?rev=311186&r1=311185&r2=311186&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/SanitizerCoverage.cpp Fri Aug 18 11:43:30 2017
@@ -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 SanCovGuardsSec
 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 @@ static cl::opt<bool>
                   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 @@ SanitizerCoverageOptions OverrideFromCL(
   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 @@ private:
   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 @@ bool SanitizerCoverageModule::runOnModul
   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 @@ bool SanitizerCoverageModule::runOnFunct
   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 @@ void SanitizerCoverageModule::InjectCove
     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

Added: llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll?rev=311186&view=auto
==============================================================================
--- llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll (added)
+++ llvm/trunk/test/Instrumentation/SanitizerCoverage/stack-depth.ll Fri Aug 18 11:43:30 2017
@@ -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
+ at __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
+}




More information about the llvm-commits mailing list