From: Yury Gribov Date: Mon, 1 Dec 2014 08:47:58 +0000 (+0000) Subject: [asan] Change dynamic alloca instrumentation to only consider allocas that are domina... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=434494196bc04087748844e2c9095a7d8ada88cb;p=oota-llvm.git [asan] Change dynamic alloca instrumentation to only consider allocas that are dominating all exits from function. Reviewed in http://reviews.llvm.org/D6412 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222991 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index dd9332c7a90..f939b96b4b5 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" @@ -348,10 +349,15 @@ static size_t RedzoneSizeForScale(int MappingScale) { /// AddressSanitizer: instrument the code in module to find memory bugs. struct AddressSanitizer : public FunctionPass { - AddressSanitizer() : FunctionPass(ID) {} + AddressSanitizer() : FunctionPass(ID) { + initializeAddressSanitizerPass(*PassRegistry::getPassRegistry()); + } const char *getPassName() const override { return "AddressSanitizerFunctionPass"; } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } void instrumentMop(Instruction *I, bool UseCalls); void instrumentPointerComparisonOrSubtraction(Instruction *I); void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, @@ -369,6 +375,8 @@ struct AddressSanitizer : public FunctionPass { bool doInitialization(Module &M) override; static char ID; // Pass identification, replacement for typeid + DominatorTree &getDominatorTree() const { return *DT; } + private: void initializeCallbacks(Module &M); @@ -380,6 +388,7 @@ struct AddressSanitizer : public FunctionPass { int LongSize; Type *IntptrTy; ShadowMapping Mapping; + DominatorTree *DT; Function *AsanCtorFunction; Function *AsanInitFunction; Function *AsanHandleNoReturnFunc; @@ -471,10 +480,11 @@ struct FunctionStackPoisoner : public InstVisitor { AllocaInst *AI; Value *LeftRzAddr; Value *RightRzAddr; + bool Poison; explicit DynamicAllocaCall(AllocaInst *AI, Value *LeftRzAddr = nullptr, Value *RightRzAddr = nullptr) - : AI(AI), LeftRzAddr(LeftRzAddr), RightRzAddr(RightRzAddr) + : AI(AI), LeftRzAddr(LeftRzAddr), RightRzAddr(RightRzAddr), Poison(true) {} }; SmallVector DynamicAllocaVec; @@ -520,6 +530,8 @@ struct FunctionStackPoisoner : public InstVisitor { // Unpoison dynamic allocas redzones. void unpoisonDynamicAlloca(DynamicAllocaCall &AllocaCall) { + if (!AllocaCall.Poison) + return; for (auto Ret : RetVec) { IRBuilder<> IRBRet(Ret); PointerType *Int32PtrTy = PointerType::getUnqual(IRBRet.getInt32Ty()); @@ -605,6 +617,14 @@ struct FunctionStackPoisoner : public InstVisitor { // ---------------------- Helpers. void initializeCallbacks(Module &M); + bool doesDominateAllExits(const Instruction *I) const { + for (auto Ret : RetVec) { + if (!ASan.getDominatorTree().dominates(I, Ret)) + return false; + } + return true; + } + bool isDynamicAlloca(AllocaInst &AI) const { return AI.isArrayAllocation() || !AI.isStaticAlloca(); } @@ -634,7 +654,11 @@ struct FunctionStackPoisoner : public InstVisitor { } // namespace char AddressSanitizer::ID = 0; -INITIALIZE_PASS(AddressSanitizer, "asan", +INITIALIZE_PASS_BEGIN(AddressSanitizer, "asan", + "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", + false, false) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_END(AddressSanitizer, "asan", "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false, false) FunctionPass *llvm::createAddressSanitizerFunctionPass() { @@ -1354,6 +1378,8 @@ bool AddressSanitizer::runOnFunction(Function &F) { DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); initializeCallbacks(*F.getParent()); + DT = &getAnalysis().getDomTree(); + // If needed, insert __asan_init before checking for SanitizeAddress attr. maybeInsertAsanInitAtFunctionEntry(F); @@ -1825,6 +1851,12 @@ Value *FunctionStackPoisoner::computePartialRzMagic(Value *PartialSize, void FunctionStackPoisoner::handleDynamicAllocaCall( DynamicAllocaCall &AllocaCall) { AllocaInst *AI = AllocaCall.AI; + if (!doesDominateAllExits(AI)) { + // We do not yet handle complex allocas + AllocaCall.Poison = false; + return; + } + IRBuilder<> IRB(AI); PointerType *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); diff --git a/test/Instrumentation/AddressSanitizer/undecidable-dynamic-alloca-1.ll b/test/Instrumentation/AddressSanitizer/undecidable-dynamic-alloca-1.ll new file mode 100644 index 00000000000..c67fb501463 --- /dev/null +++ b/test/Instrumentation/AddressSanitizer/undecidable-dynamic-alloca-1.ll @@ -0,0 +1,23 @@ +; Test that undecidable dynamic allocas are skipped by ASan. + +; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s +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" + +define void @g(i64 %n) sanitize_address { +entry: + %cmp = icmp sgt i64 %n, 100 + br i1 %cmp, label %do_alloca, label %done + +do_alloca: +; CHECK-NOT: store i32 -892679478 + %0 = alloca i8, i64 %n, align 1 + call void @f(i8* %0) + br label %done + +done: + ret void +} + +declare void @f(i8*) +