Skip to content

Commit

Permalink
[ASan] Enable optional ASan recovery.
Browse files Browse the repository at this point in the history
Differential Revision: http://reviews.llvm.org/D14242


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252719 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Yury Gribov committed Nov 11, 2015
1 parent 520fef2 commit 2660d58
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 20 deletions.
6 changes: 4 additions & 2 deletions include/llvm/Transforms/Instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ ModulePass *createInstrProfilingPass(
const InstrProfOptions &Options = InstrProfOptions());

// Insert AddressSanitizer (address sanity checking) instrumentation
FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false);
ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false);
FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
bool Recover = false);
ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
bool Recover = false);

// Insert MemorySanitizer instrumentation (detection of uninitialized reads)
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0);
Expand Down
51 changes: 33 additions & 18 deletions lib/Transforms/Instrumentation/AddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ static const unsigned kAllocaRzSize = 32;
static cl::opt<bool> ClEnableKasan(
"asan-kernel", cl::desc("Enable KernelAddressSanitizer instrumentation"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClRecover(
"asan-recover",
cl::desc("Enable recovery mode (continue-after-error)."),
cl::Hidden, cl::init(false));

// This flag may need to be replaced with -f[no-]asan-reads.
static cl::opt<bool> ClInstrumentReads("asan-instrument-reads",
Expand Down Expand Up @@ -395,8 +399,9 @@ static size_t RedzoneSizeForScale(int MappingScale) {

/// AddressSanitizer: instrument the code in module to find memory bugs.
struct AddressSanitizer : public FunctionPass {
explicit AddressSanitizer(bool CompileKernel = false)
: FunctionPass(ID), CompileKernel(CompileKernel || ClEnableKasan) {
explicit AddressSanitizer(bool CompileKernel = false, bool Recover = false)
: FunctionPass(ID), CompileKernel(CompileKernel || ClEnableKasan),
Recover(Recover || ClRecover) {
initializeAddressSanitizerPass(*PassRegistry::getPassRegistry());
}
const char *getPassName() const override {
Expand Down Expand Up @@ -471,6 +476,7 @@ struct AddressSanitizer : public FunctionPass {
Triple TargetTriple;
int LongSize;
bool CompileKernel;
bool Recover;
Type *IntptrTy;
ShadowMapping Mapping;
DominatorTree *DT;
Expand All @@ -494,8 +500,10 @@ struct AddressSanitizer : public FunctionPass {

class AddressSanitizerModule : public ModulePass {
public:
explicit AddressSanitizerModule(bool CompileKernel = false)
: ModulePass(ID), CompileKernel(CompileKernel || ClEnableKasan) {}
explicit AddressSanitizerModule(bool CompileKernel = false,
bool Recover = false)
: ModulePass(ID), CompileKernel(CompileKernel || ClEnableKasan),
Recover(Recover || ClRecover) {}
bool runOnModule(Module &M) override;
static char ID; // Pass identification, replacement for typeid
const char *getPassName() const override { return "AddressSanitizerModule"; }
Expand All @@ -513,6 +521,7 @@ class AddressSanitizerModule : public ModulePass {

GlobalsMetadata GlobalsMD;
bool CompileKernel;
bool Recover;
Type *IntptrTy;
LLVMContext *C;
Triple TargetTriple;
Expand Down Expand Up @@ -729,8 +738,10 @@ INITIALIZE_PASS_END(
AddressSanitizer, "asan",
"AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
false)
FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel) {
return new AddressSanitizer(CompileKernel);
FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel,
bool Recover) {
assert(!CompileKernel || Recover);
return new AddressSanitizer(CompileKernel, Recover);
}

char AddressSanitizerModule::ID = 0;
Expand All @@ -739,8 +750,10 @@ INITIALIZE_PASS(
"AddressSanitizer: detects use-after-free and out-of-bounds bugs."
"ModulePass",
false, false)
ModulePass *llvm::createAddressSanitizerModulePass(bool CompileKernel) {
return new AddressSanitizerModule(CompileKernel);
ModulePass *llvm::createAddressSanitizerModulePass(bool CompileKernel,
bool Recover) {
assert(!CompileKernel || Recover);
return new AddressSanitizerModule(CompileKernel, Recover);
}

static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
Expand Down Expand Up @@ -1069,13 +1082,17 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
BasicBlock *NextBB = CheckTerm->getSuccessor(0);
IRB.SetInsertPoint(CheckTerm);
Value *Cmp2 = createSlowPathCmp(IRB, AddrLong, ShadowValue, TypeSize);
BasicBlock *CrashBlock =
if (Recover) {
CrashTerm = SplitBlockAndInsertIfThen(Cmp2, CheckTerm, false);
} else {
BasicBlock *CrashBlock =
BasicBlock::Create(*C, "", NextBB->getParent(), NextBB);
CrashTerm = new UnreachableInst(*C, CrashBlock);
BranchInst *NewTerm = BranchInst::Create(CrashBlock, NextBB, Cmp2);
ReplaceInstWithInst(CheckTerm, NewTerm);
CrashTerm = new UnreachableInst(*C, CrashBlock);
BranchInst *NewTerm = BranchInst::Create(CrashBlock, NextBB, Cmp2);
ReplaceInstWithInst(CheckTerm, NewTerm);
}
} else {
CrashTerm = SplitBlockAndInsertIfThen(Cmp, InsertBefore, true);
CrashTerm = SplitBlockAndInsertIfThen(Cmp, InsertBefore, !Recover);
}

Instruction *Crash = generateCrashCode(CrashTerm, AddrLong, IsWrite,
Expand Down Expand Up @@ -1420,13 +1437,11 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
const std::string TypeStr = AccessIsWrite ? "store" : "load";
const std::string ExpStr = Exp ? "exp_" : "";
const std::string SuffixStr = CompileKernel ? "N" : "_n";
const std::string EndingStr = CompileKernel ? "_noabort" : "";
const std::string EndingStr = Recover ? "_noabort" : "";
Type *ExpType = Exp ? Type::getInt32Ty(*C) : nullptr;
// TODO(glider): for KASan builds add _noabort to error reporting
// functions and make them actually noabort (remove the UnreachableInst).
AsanErrorCallbackSized[AccessIsWrite][Exp] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
kAsanReportErrorTemplate + ExpStr + TypeStr + SuffixStr,
kAsanReportErrorTemplate + ExpStr + TypeStr + SuffixStr + EndingStr,
IRB.getVoidTy(), IntptrTy, IntptrTy, ExpType, nullptr));
AsanMemoryAccessCallbackSized[AccessIsWrite][Exp] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Expand All @@ -1437,7 +1452,7 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
const std::string Suffix = TypeStr + itostr(1 << AccessSizeIndex);
AsanErrorCallback[AccessIsWrite][Exp][AccessSizeIndex] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
kAsanReportErrorTemplate + ExpStr + Suffix,
kAsanReportErrorTemplate + ExpStr + Suffix + EndingStr,
IRB.getVoidTy(), IntptrTy, ExpType, nullptr));
AsanMemoryAccessCallback[AccessIsWrite][Exp][AccessSizeIndex] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Expand Down
14 changes: 14 additions & 0 deletions test/Instrumentation/AddressSanitizer/keep_going.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
; Test asan internal compiler flags:
; -asan-recover=1

; RUN: opt < %s -asan -asan-recover -asan-module -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 i32 @foo(i32* %p) sanitize_address {
; CHECK: __asan_report_load4_noabort
; CHECK-NOT: unreachable
%1 = load i32, i32* %p, align 4
ret i32 %1
}

0 comments on commit 2660d58

Please sign in to comment.