From: Vitaly Buka Date: Sat, 20 Aug 2016 20:23:50 +0000 (+0000) Subject: [asan] Minimize code size by using __asan_set_shadow_* for large blocks X-Git-Tag: llvmorg-4.0.0-rc1~11814 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1f9e135023695062f0d46b15f8a6aa03a68dc1d9;p=platform%2Fupstream%2Fllvm.git [asan] Minimize code size by using __asan_set_shadow_* for large blocks Summary: We can insert function call instead of multiple store operation. Current default is blocks larger than 64 bytes. Changes are hidden behind -asan-experimental-poisoning flag. PR27453 Differential Revision: https://reviews.llvm.org/D23711 llvm-svn: 279383 --- diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index dde544d..7bf958e 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -167,6 +167,11 @@ static cl::opt ClMaxInsnsToInstrumentPerBB( // 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 @@ struct FunctionStackPoisoner : public InstVisitor { /// 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 @@ void FunctionStackPoisoner::initializeCallbacks(Module &M) { // 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 @@ void FunctionStackPoisoner::poisonStackFrame(ArrayRef ShadowBytes, // 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, } } +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) { diff --git a/llvm/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll b/llvm/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll index bf3cf9c..a9dd83a 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll +++ b/llvm/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 @@ declare void @Foo(i8*) 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: