[llvm] r279383 - [asan] Minimize code size by using __asan_set_shadow_* for large blocks
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 20 13:23:51 PDT 2016
Author: vitalybuka
Date: Sat Aug 20 15:23:50 2016
New Revision: 279383
URL: http://llvm.org/viewvc/llvm-project?rev=279383&view=rev
Log:
[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
Modified:
llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll
Modified: llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp?rev=279383&r1=279382&r2=279383&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp Sat Aug 20 15:23:50 2016
@@ -167,6 +167,11 @@ static cl::opt<int> ClMaxInsnsToInstrume
// This flag may need to be replaced with -f[no]asan-stack.
static cl::opt<bool> ClStack("asan-stack", cl::desc("Handle stack memory"),
cl::Hidden, cl::init(true));
+static cl::opt<uint32_t> 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<bool> ClUseAfterReturn("asan-use-after-return",
cl::desc("Check stack-use-after-return"),
cl::Hidden, cl::init(true));
@@ -806,6 +811,9 @@ struct FunctionStackPoisoner : public In
/// Finds alloca where the value comes from.
AllocaInst *findAllocaForValue(Value *V);
+ void poisonStackFrameInline(ArrayRef<uint8_t> ShadowBytes, size_t Begin,
+ size_t End, IRBuilder<> &IRB, Value *ShadowBase,
+ bool DoPoison);
void poisonStackFrame(ArrayRef<uint8_t> ShadowBytes, IRBuilder<> &IRB,
Value *ShadowBase, bool DoPoison);
void poisonAlloca(Value *V, uint64_t Size, IRBuilder<> &IRB, bool DoPoison);
@@ -1956,10 +1964,11 @@ void FunctionStackPoisoner::initializeCa
// 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<uint8_t> ShadowBytes,
- IRBuilder<> &IRB,
- Value *ShadowBase, bool DoPoison) {
- const size_t End = ShadowBytes.size();
+void FunctionStackPoisoner::poisonStackFrameInline(
+ ArrayRef<uint8_t> ShadowBytes, size_t Begin, size_t End, IRBuilder<> &IRB,
+ Value *ShadowBase, bool DoPoison) {
+ if (Begin >= End)
+ return;
const size_t LargestStoreSizeInBytes =
std::min<size_t>(sizeof(uint64_t), ASan.LongSize / 8);
@@ -1970,7 +1979,7 @@ void FunctionStackPoisoner::poisonStackF
// 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::poisonStackF
}
}
+void FunctionStackPoisoner::poisonStackFrame(ArrayRef<uint8_t> ShadowBytes,
+ IRBuilder<> &IRB,
+ Value *ShadowBase, bool DoPoison) {
+ auto ValueToWrite = [&](size_t i) {
+ if (DoPoison)
+ return ShadowBytes[i];
+ return static_cast<uint8_t>(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) {
Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll?rev=279383&r1=279382&r2=279383&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-experimental.ll Sat Aug 20 15:23:50 2016
@@ -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: <label>
+ ; CHECK-ON-NOT: store i64
+ ; CHECK-ON: call void @__asan_set_shadow_f5(i64 %{{[0-9]+}}, i64 128)
+
+ ; CHECK-OFF-NOT: call void @__asan_set_shadow_f5
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; CHECK-OFF: store i64 -723401728380766731
+ ; And more...
+
+ ; CHECK-LABEL: <label>
+ ; CHECK-NOT: call void @__asan_set_shadow_00
+ ; CHECK: store i32 0
+ ; CHECK: store i64 0
+ ; CHECK: store i64 0
+ ; CHECK: store i16 0
+ ; CHECK: store i8 0
+
+ ; CHECK-LABEL: <label>
+ ; CHECK: ret void
+
+ %x = alloca [650 x i8], align 16
+ %arraydecay = getelementptr inbounds [650 x i8], [650 x i8]* %x, i64 0, i64 0
call void @Foo(i8* %arraydecay)
ret void
}
-; CHECK: declare void @__asan_set_shadow_00(i64, i64)
-; CHECK: declare void @__asan_set_shadow_f1(i64, i64)
-; CHECK: declare void @__asan_set_shadow_f2(i64, i64)
-; CHECK: declare void @__asan_set_shadow_f3(i64, i64)
-; CHECK: declare void @__asan_set_shadow_f5(i64, i64)
-; CHECK: declare void @__asan_set_shadow_f8(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_00(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_f1(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_f2(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_f3(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_f5(i64, i64)
+; CHECK-ON: declare void @__asan_set_shadow_f8(i64, i64)
; CHECK-OFF-NOT: declare void @__asan_set_shadow_
More information about the llvm-commits
mailing list