Skip to content

Commit

Permalink
[asan] Cleanup instrumentation of dynamic allocas
Browse files Browse the repository at this point in the history
Summary:
Extract instrumenting dynamic allocas into separate method.
Rename asan-instrument-allocas -> asan-instrument-dynamic-allocas

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

llvm-svn: 279376
  • Loading branch information
vitalybuka committed Aug 20, 2016
1 parent cb0ba10 commit 5b4f121
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 29 deletions.
68 changes: 44 additions & 24 deletions llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
Expand Up @@ -196,9 +196,10 @@ static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
"asan-memory-access-callback-prefix",
cl::desc("Prefix for memory access callbacks"), cl::Hidden,
cl::init("__asan_"));
static cl::opt<bool> ClInstrumentAllocas("asan-instrument-allocas",
cl::desc("instrument dynamic allocas"),
cl::Hidden, cl::init(true));
static cl::opt<bool>
ClInstrumentDynamicAllocas("asan-instrument-dynamic-allocas",
cl::desc("instrument dynamic allocas"),
cl::Hidden, cl::init(true));
static cl::opt<bool> ClSkipPromotableAllocas(
"asan-skip-promotable-allocas",
cl::desc("Do not instrument promotable allocas"), cl::Hidden,
Expand Down Expand Up @@ -622,7 +623,8 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
uint64_t Size;
bool DoPoison;
};
SmallVector<AllocaPoisonCall, 8> AllocaPoisonCallVec;
SmallVector<AllocaPoisonCall, 8> DynamicAllocaPoisonCallVec;
SmallVector<AllocaPoisonCall, 8> StaticAllocaPoisonCallVec;

SmallVector<AllocaInst *, 1> DynamicAllocaVec;
SmallVector<IntrinsicInst *, 1> StackRestoreVec;
Expand Down Expand Up @@ -657,7 +659,8 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {

initializeCallbacks(*F.getParent());

poisonStack();
processDynamicAllocas();
processStaticAllocas();

if (ClDebugStack) {
DEBUG(dbgs() << F);
Expand All @@ -668,7 +671,8 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
// Finds all Alloca instructions and puts
// poisoned red zones around all of them.
// Then unpoison everything back before the function returns.
void poisonStack();
void processStaticAllocas();
void processDynamicAllocas();

void createDynamicAllocasInitStorage();

Expand Down Expand Up @@ -767,7 +771,10 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
return;
bool DoPoison = (ID == Intrinsic::lifetime_end);
AllocaPoisonCall APC = {&II, AI, SizeValue, DoPoison};
AllocaPoisonCallVec.push_back(APC);
if (AI->isStaticAlloca())
StaticAllocaPoisonCallVec.push_back(APC);
else if (ClInstrumentDynamicAllocas)
DynamicAllocaPoisonCallVec.push_back(APC);
}

void visitCallSite(CallSite CS) {
Expand Down Expand Up @@ -2021,37 +2028,39 @@ void FunctionStackPoisoner::createDynamicAllocasInitStorage() {
DynamicAllocaLayout->setAlignment(32);
}

void FunctionStackPoisoner::poisonStack() {
assert(AllocaVec.size() > 0 || DynamicAllocaVec.size() > 0);
void FunctionStackPoisoner::processDynamicAllocas() {
if (!ClInstrumentDynamicAllocas || DynamicAllocaVec.empty()) {
assert(DynamicAllocaPoisonCallVec.empty());
return;
}

// Insert poison calls for lifetime intrinsics for alloca.
bool HavePoisonedStaticAllocas = false;
for (const auto &APC : AllocaPoisonCallVec) {
// Insert poison calls for lifetime intrinsics for dynamic allocas.
for (const auto &APC : DynamicAllocaPoisonCallVec) {
assert(APC.InsBefore);
assert(APC.AI);
assert(ASan.isInterestingAlloca(*APC.AI));
bool IsDynamicAlloca = !(*APC.AI).isStaticAlloca();
if (!ClInstrumentAllocas && IsDynamicAlloca)
continue;
assert(!APC.AI->isStaticAlloca());

IRBuilder<> IRB(APC.InsBefore);
poisonAlloca(APC.AI, APC.Size, IRB, APC.DoPoison);
// Dynamic allocas will be unpoisoned unconditionally below in
// unpoisonDynamicAllocas.
// Flag that we need unpoison static allocas.
HavePoisonedStaticAllocas |= (APC.DoPoison && !IsDynamicAlloca);
}

if (ClInstrumentAllocas && DynamicAllocaVec.size() > 0) {
// Handle dynamic allocas.
createDynamicAllocasInitStorage();
for (auto &AI : DynamicAllocaVec) handleDynamicAllocaCall(AI);
// Handle dynamic allocas.
createDynamicAllocasInitStorage();
for (auto &AI : DynamicAllocaVec)
handleDynamicAllocaCall(AI);
unpoisonDynamicAllocas();
}

unpoisonDynamicAllocas();
void FunctionStackPoisoner::processStaticAllocas() {
if (AllocaVec.empty()) {
assert(StaticAllocaPoisonCallVec.empty());
return;
}

if (AllocaVec.empty()) return;

int StackMallocIdx = -1;
DebugLoc EntryDebugLocation;
if (auto SP = F.getSubprogram())
Expand All @@ -2074,6 +2083,17 @@ void FunctionStackPoisoner::poisonStack() {
// If we have a call to llvm.localescape, keep it in the entry block.
if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore);

// Insert poison calls for lifetime intrinsics for static allocas.
for (const auto &APC : StaticAllocaPoisonCallVec) {
assert(APC.InsBefore);
assert(APC.AI);
assert(ASan.isInterestingAlloca(*APC.AI));
assert(APC.AI->isStaticAlloca());

IRBuilder<> IRB(APC.InsBefore);
poisonAlloca(APC.AI, APC.Size, IRB, APC.DoPoison);
}

SmallVector<ASanStackVariableDescription, 16> SVD;
SVD.reserve(AllocaVec.size());
for (AllocaInst *AI : AllocaVec) {
Expand Down Expand Up @@ -2192,7 +2212,7 @@ void FunctionStackPoisoner::poisonStack() {
// Do this always as poisonAlloca can be disabled with
// detect_stack_use_after_scope=0.
poisonRedZones(L.ShadowBytes, IRB, ShadowBase, false);
if (HavePoisonedStaticAllocas) {
if (!StaticAllocaPoisonCallVec.empty()) {
// If we poisoned some allocas in llvm.lifetime analysis,
// unpoison whole stack frame now.
poisonAlloca(LocalStackBase, LocalStackSize, IRB, false);
Expand Down
Expand Up @@ -3,7 +3,7 @@
; breaks debug info.

; RUN: opt < %s -asan -asan-module -S | FileCheck %s
; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s
; RUN: opt < %s -asan -asan-module -asan-instrument-dynamic-allocas -S | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"
Expand Down
@@ -1,4 +1,4 @@
; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s
; RUN: opt < %s -asan -asan-module -asan-instrument-dynamic-allocas -S | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"
Expand Down
@@ -1,7 +1,7 @@
; Test asan internal compiler flags:
; -asan-instrument-allocas=1
; -asan-instrument-dynamic-allocas

; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s --check-prefix=CHECK-ALLOCA
; RUN: opt < %s -asan -asan-module -asan-instrument-dynamic-allocas -S | FileCheck %s --check-prefix=CHECK-ALLOCA
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Instrumentation/AddressSanitizer/lifetime.ll
@@ -1,6 +1,6 @@
; Test handling of llvm.lifetime intrinsics.
; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -S | FileCheck %s
; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -asan-instrument-allocas=0 -S | FileCheck %s --check-prefix=CHECK-NO-DYNAMIC
; RUN: opt < %s -asan -asan-module -asan-use-after-scope -asan-use-after-return=0 -asan-instrument-dynamic-allocas=0 -S | FileCheck %s --check-prefix=CHECK-NO-DYNAMIC

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
Expand Down

0 comments on commit 5b4f121

Please sign in to comment.