Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -49,6 +49,7 @@ #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/Transforms/Utils/PromoteMemToReg.h" #include #include #include @@ -165,6 +166,9 @@ cl::init("__asan_")); static cl::opt ClInstrumentAllocas("asan-instrument-allocas", cl::desc("instrument dynamic allocas"), cl::Hidden, cl::init(false)); +static cl::opt ClSkipPromotableAllocas("asan-skip-promotable-allocas", + cl::desc("Do not instrument promotable allocas"), + cl::Hidden, cl::init(true)); // These flags allow to change the shadow mapping. // The shadow mapping looks like @@ -658,7 +662,10 @@ bool isInterestingAlloca(AllocaInst &AI) const { return (AI.getAllocatedType()->isSized() && // alloca() may be called with 0 size, ignore it. - getAllocaSizeInBytes(&AI) > 0); + getAllocaSizeInBytes(&AI) > 0 && + // We are only interested in allocas not promotable to registers. + // Promotable allocas are common under -O0. + (!ClSkipPromotableAllocas || !isAllocaPromotable(&AI))); } uint64_t getAllocaSizeInBytes(AllocaInst *AI) const { @@ -782,31 +789,41 @@ // Skip memory accesses inserted by another instrumentation. if (I->getMetadata("nosanitize")) return nullptr; + + Value *PtrOperand = nullptr; if (LoadInst *LI = dyn_cast(I)) { if (!ClInstrumentReads) return nullptr; *IsWrite = false; *Alignment = LI->getAlignment(); - return LI->getPointerOperand(); + PtrOperand = LI->getPointerOperand(); } if (StoreInst *SI = dyn_cast(I)) { if (!ClInstrumentWrites) return nullptr; *IsWrite = true; *Alignment = SI->getAlignment(); - return SI->getPointerOperand(); + PtrOperand = SI->getPointerOperand(); } if (AtomicRMWInst *RMW = dyn_cast(I)) { if (!ClInstrumentAtomics) return nullptr; *IsWrite = true; *Alignment = 0; - return RMW->getPointerOperand(); + PtrOperand = RMW->getPointerOperand(); } if (AtomicCmpXchgInst *XCHG = dyn_cast(I)) { if (!ClInstrumentAtomics) return nullptr; *IsWrite = true; *Alignment = 0; - return XCHG->getPointerOperand(); + PtrOperand = XCHG->getPointerOperand(); } - return nullptr; + + // Treat memory accesses to promotable allocas as non-interesting since they + // are not likely to cause memory violations. This greatly speeds up + // the instrumented executable at -O0. + if (auto AI = dyn_cast_or_null(PtrOperand)) + if (ClSkipPromotableAllocas) + return isAllocaPromotable(AI) ? nullptr : AI; + + return PtrOperand; } static bool isPointerOperand(Value *V) { Index: test/Instrumentation/AddressSanitizer/debug_info.ll =================================================================== --- test/Instrumentation/AddressSanitizer/debug_info.ll +++ test/Instrumentation/AddressSanitizer/debug_info.ll @@ -10,12 +10,12 @@ entry: %p.addr = alloca i32, align 4 %r = alloca i32, align 4 - store i32 %p, i32* %p.addr, align 4 + store volatile i32 %p, i32* %p.addr, align 4 call void @llvm.dbg.declare(metadata i32* %p.addr, metadata !10, metadata !{!"0x102"}), !dbg !11 call void @llvm.dbg.declare(metadata i32* %r, metadata !12, metadata !{!"0x102"}), !dbg !14 %0 = load i32* %p.addr, align 4, !dbg !14 %add = add nsw i32 %0, 1, !dbg !14 - store i32 %add, i32* %r, align 4, !dbg !14 + store volatile i32 %add, i32* %r, align 4, !dbg !14 %1 = load i32* %r, align 4, !dbg !15 ret i32 %1, !dbg !15 } Index: test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll =================================================================== --- /dev/null +++ test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s --check-prefix=CHECK + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.10.0" + +define i32 @test_promotable_allocas() sanitize_address { +entry: +; CHECK: %0 = alloca i32, align 4 +; CHECK: store i32 0, i32* %0, align 4 +; CHECK: %1 = load i32* %0, align 4 +; CHECK: ret i32 %1 + +; CHECK-NOT: __asan_stack_malloc_0 +; CHECK-NOT: icmp +; CHECK-NOT: call void @__asan_report_store4 + + %0 = alloca i32, align 4 + store i32 0, i32* %0, align 4 + %1 = load i32* %0, align 4 + ret i32 %1 +} Index: test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll =================================================================== --- test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll +++ test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll @@ -15,10 +15,11 @@ ; CHECK-NOALLOCA-NOT: store i32 -875836469 %0 = alloca i32, align 4 %1 = alloca i8* - store i32 %len, i32* %0, align 4 + store volatile i32 %len, i32* %0, align 4 %2 = load i32* %0, align 4 %3 = zext i32 %2 to i64 %4 = alloca i8, i64 %3, align 32 + store volatile i8 0, i8* %4 ret void } Index: test/Instrumentation/AddressSanitizer/lifetime-uar.ll =================================================================== --- test/Instrumentation/AddressSanitizer/lifetime-uar.ll +++ test/Instrumentation/AddressSanitizer/lifetime-uar.ll @@ -17,8 +17,8 @@ ; Memory is unpoisoned at llvm.lifetime.start ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 1) - store i32 0, i32* %retval - store i8 0, i8* %c, align 1 + store volatile i32 0, i32* %retval + store volatile i8 0, i8* %c, align 1 call void @llvm.lifetime.end(i64 1, i8* %c) ; Memory is poisoned at llvm.lifetime.end Index: test/Instrumentation/AddressSanitizer/lifetime.ll =================================================================== --- test/Instrumentation/AddressSanitizer/lifetime.ll +++ test/Instrumentation/AddressSanitizer/lifetime.ll @@ -12,6 +12,7 @@ %i = alloca i32, align 4 %i.ptr = bitcast i32* %i to i8* call void @llvm.lifetime.start(i64 -1, i8* %i.ptr) + store volatile i8 0, i8* %i.ptr call void @llvm.lifetime.end(i64 -1, i8* %i.ptr) ; Check that lifetime with no size are ignored. @@ -30,6 +31,7 @@ %i = alloca i32, align 4 %i.ptr = bitcast i32* %i to i8* call void @llvm.lifetime.start(i64 3, i8* %i.ptr) + store volatile i8 0, i8* %i.ptr ; Memory is unpoisoned at llvm.lifetime.start ; CHECK: %[[VAR:[^ ]*]] = ptrtoint i32* %{{[^ ]+}} to i64 ; CHECK-NEXT: call void @__asan_unpoison_stack_memory(i64 %[[VAR]], i64 3) @@ -43,12 +45,14 @@ %arr = alloca [10 x i32], align 16 %arr.ptr = bitcast [10 x i32]* %arr to i8* call void @llvm.lifetime.start(i64 40, i8* %arr.ptr) + store volatile i8 0, i8* %arr.ptr ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 40) call void @llvm.lifetime.end(i64 40, i8* %arr.ptr) ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 40) ; One more lifetime start/end for the same variable %i. call void @llvm.lifetime.start(i64 4, i8* %i.ptr) + store volatile i8 0, i8* %i.ptr ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 4) call void @llvm.lifetime.end(i64 4, i8* %i.ptr) ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4) @@ -68,6 +72,7 @@ %i = alloca i64, align 4 %i.ptr = bitcast i64* %i to i8* call void @llvm.lifetime.start(i64 8, i8* %i.ptr) + store volatile i8 0, i8* %i.ptr ; CHECK: __asan_unpoison_stack_memory br i1 %x, label %bb0, label %bb1 Index: test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll =================================================================== --- test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll +++ test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll @@ -26,6 +26,8 @@ ; CHECK: ret void %XXX = alloca [20 x i8], align 1 + %arr.ptr = bitcast [20 x i8]* %XXX to i8* + store volatile i8 0, i8* %arr.ptr ret void } @@ -37,6 +39,8 @@ ; CHECK: ret void %XXX = alloca [20 x i8], align 1 + %arr.ptr = bitcast [20 x i8]* %XXX to i8* + store volatile i8 0, i8* %arr.ptr call void asm sideeffect "mov %%rbx, %%rcx", "~{dirflag},~{fpsr},~{flags}"() nounwind ret void } Index: test/Instrumentation/AddressSanitizer/stack_layout.ll =================================================================== --- test/Instrumentation/AddressSanitizer/stack_layout.ll +++ test/Instrumentation/AddressSanitizer/stack_layout.ll @@ -26,6 +26,12 @@ %XXX = alloca [10 x i8], align 1 %YYY = alloca [20 x i8], align 1 %ZZZ = alloca [30 x i8], align 1 + %arr1.ptr = bitcast [10 x i8]* %XXX to i8* + store volatile i8 0, i8* %arr1.ptr + %arr2.ptr = bitcast [20 x i8]* %YYY to i8* + store volatile i8 0, i8* %arr2.ptr + %arr3.ptr = bitcast [30 x i8]* %ZZZ to i8* + store volatile i8 0, i8* %arr3.ptr ret void } @@ -41,6 +47,12 @@ %AAA = alloca [5 x i8], align 1 %BBB = alloca [55 x i8], align 1 %CCC = alloca [555 x i8], align 1 + %arr1.ptr = bitcast [5 x i8]* %AAA to i8* + store volatile i8 0, i8* %arr1.ptr + %arr2.ptr = bitcast [55 x i8]* %BBB to i8* + store volatile i8 0, i8* %arr2.ptr + %arr3.ptr = bitcast [555 x i8]* %CCC to i8* + store volatile i8 0, i8* %arr3.ptr ret void } @@ -57,5 +69,11 @@ %AAA = alloca [128 x i8], align 16 %BBB = alloca [128 x i8], align 64 %CCC = alloca [128 x i8], align 256 + %arr1.ptr = bitcast [128 x i8]* %AAA to i8* + store volatile i8 0, i8* %arr1.ptr + %arr2.ptr = bitcast [128 x i8]* %BBB to i8* + store volatile i8 0, i8* %arr2.ptr + %arr3.ptr = bitcast [128 x i8]* %CCC to i8* + store volatile i8 0, i8* %arr3.ptr ret void }