Index: llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -167,6 +167,11 @@ // This flag may need to be replaced with -f[no]asan-stack. static cl::opt ClStack("asan-stack", cl::desc("Handle stack memory"), cl::Hidden, cl::init(true)); +static cl::opt ClMaxInlinePoisoningSize( + "asan-max-inline-poisoning-size", + cl::desc( + "Inline shadow poisoning for blocks up to the given size in bytes."), + cl::Hidden, cl::init(64)); static cl::opt ClUseAfterReturn("asan-use-after-return", cl::desc("Check stack-use-after-return"), cl::Hidden, cl::init(true)); @@ -806,6 +811,9 @@ /// Finds alloca where the value comes from. AllocaInst *findAllocaForValue(Value *V); + void poisonStackFrameInline(ArrayRef ShadowBytes, size_t Begin, + size_t End, IRBuilder<> &IRB, Value *ShadowBase, + bool DoPoison); void poisonStackFrame(ArrayRef ShadowBytes, IRBuilder<> &IRB, Value *ShadowBase, bool DoPoison); void poisonAlloca(Value *V, uint64_t Size, IRBuilder<> &IRB, bool DoPoison); @@ -1956,10 +1964,11 @@ // memory is constant for duration of the function and it contains 0s. So we // will try to minimize writes into corresponding addresses of the real shadow // memory. -void FunctionStackPoisoner::poisonStackFrame(ArrayRef ShadowBytes, - IRBuilder<> &IRB, - Value *ShadowBase, bool DoPoison) { - const size_t End = ShadowBytes.size(); +void FunctionStackPoisoner::poisonStackFrameInline( + ArrayRef ShadowBytes, size_t Begin, size_t End, IRBuilder<> &IRB, + Value *ShadowBase, bool DoPoison) { + if (Begin >= End) + return; const size_t LargestStoreSizeInBytes = std::min(sizeof(uint64_t), ASan.LongSize / 8); @@ -1970,7 +1979,7 @@ // trailing zeros. Zeros never change, so they need neither poisoning nor // up-poisoning, but we don't mind if some of them get into a middle of a // store. - for (size_t i = 0; i < End;) { + for (size_t i = Begin; i < End;) { if (!ShadowBytes[i]) { ++i; continue; @@ -2009,6 +2018,40 @@ } } +void FunctionStackPoisoner::poisonStackFrame(ArrayRef ShadowBytes, + IRBuilder<> &IRB, + Value *ShadowBase, bool DoPoison) { + auto ValueToWrite = [&](size_t i) { + if (DoPoison) + return ShadowBytes[i]; + return static_cast(0); + }; + + const size_t End = ShadowBytes.size(); + size_t Done = 0; + for (size_t i = 0, j = 1; i < End; i = j++) { + if (!ShadowBytes[i]) + continue; + uint8_t Val = ValueToWrite(i); + if (!AsanSetShadowFunc[Val]) + continue; + + // Skip same values. + for (; j < End && ShadowBytes[j] && Val == ValueToWrite(j); ++j) { + } + + if (j - i >= ClMaxInlinePoisoningSize) { + poisonStackFrameInline(ShadowBytes, Done, i, IRB, ShadowBase, DoPoison); + IRB.CreateCall(AsanSetShadowFunc[Val], + {IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i)), + ConstantInt::get(IntptrTy, j - i)}); + Done = j; + } + } + + poisonStackFrameInline(ShadowBytes, Done, End, IRB, ShadowBase, DoPoison); +} + // Fake stack allocator (asan_fake_stack.h) has 11 size classes // for every power of 2 from kMinStackMallocSize to kMaxAsanStackMallocSizeClass static int StackMallocSizeClass(uint64_t LocalStackSize) { Index: llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll =================================================================== --- llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll +++ llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -asan -asan-module -asan-experimental-poisoning -S | FileCheck %s -; RUN: opt < %s -asan -asan-module -S | FileCheck --check-prefix=CHECK-OFF %s +; RUN: opt < %s -asan -asan-module -asan-experimental-poisoning -S | FileCheck --check-prefixes=CHECK-ON,CHECK %s +; RUN: opt < %s -asan -asan-module -S | FileCheck --check-prefixes=CHECK-OFF,CHECK %s target datalayout = "e-i64:64-f80:128-s:64-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -8,17 +8,52 @@ define void @Bar() uwtable sanitize_address { entry: - %x = alloca [20 x i8], align 16 - %arraydecay = getelementptr inbounds [20 x i8], [20 x i8]* %x, i64 0, i64 0 + ; CHECK: store i32 -235802127 + ; CHECK: store i64 -868082074056920318 + ; CHECK: store i64 -868082074056920077 + ; CHECK: store i16 -3085 + ; CHECK: store i8 -13 + ; CHECK-LABEL: call void @Foo + + ; CHECK-LABEL: