[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
This commit is contained in:
Yury Gribov 2014-12-01 08:47:58 +00:00
parent eed2e8bf98
commit 434494196b
2 changed files with 58 additions and 3 deletions

View File

@ -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<DominatorTreeWrapperPass>();
}
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<FunctionStackPoisoner> {
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<DynamicAllocaCall, 1> DynamicAllocaVec;
@ -520,6 +530,8 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
// 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<FunctionStackPoisoner> {
// ---------------------- 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<FunctionStackPoisoner> {
} // 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<DominatorTreeWrapperPass>().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());

View File

@ -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*)