Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 0c6c3b2

Browse files
committed
[asan] Optimize store size in FunctionStackPoisoner::poisonRedZones
Summary: Reduce store size to avoid leading and trailing zeros. Reviewers: kcc, eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D23648 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279178 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0f27e30 commit 0c6c3b2

File tree

4 files changed

+63
-47
lines changed

4 files changed

+63
-47
lines changed

include/llvm/Transforms/Utils/ASanStackFrameLayout.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class AllocaInst;
2424
static const int kAsanStackLeftRedzoneMagic = 0xf1;
2525
static const int kAsanStackMidRedzoneMagic = 0xf2;
2626
static const int kAsanStackRightRedzoneMagic = 0xf3;
27+
static const int kAsanStackUseAfterReturnMagic = 0xf5;
2728
static const int kAsanStackUseAfterScopeMagic = 0xf8;
2829

2930
// Input/output data struct for ComputeASanStackFrameLayout.

lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -795,8 +795,6 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
795795
Value *ShadowBase, bool DoPoison);
796796
void poisonAlloca(Value *V, uint64_t Size, IRBuilder<> &IRB, bool DoPoison);
797797

798-
void SetShadowToStackAfterReturnInlined(IRBuilder<> &IRB, Value *ShadowBase,
799-
int Size);
800798
Value *createAllocaForLayout(IRBuilder<> &IRB, const ASanStackFrameLayout &L,
801799
bool Dynamic);
802800
PHINode *createPHI(IRBuilder<> &IRB, Value *Cond, Value *ValueIfTrue,
@@ -1926,30 +1924,62 @@ void FunctionStackPoisoner::initializeCallbacks(Module &M) {
19261924
kAsanAllocasUnpoison, IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr));
19271925
}
19281926

1927+
// If DoPoison is true function copies ShadowBytes into shadow memory.
1928+
// If DoPoison is false function sets 0s into shadow memory.
1929+
// Function assumes that if ShadowBytes[i] is 0, then corresponding shadow
1930+
// memory is constant for duration of the function and it contains 0s. So we
1931+
// will try to minimize writes into corresponding addresses of the real shadow
1932+
// memory.
19291933
void FunctionStackPoisoner::poisonRedZones(ArrayRef<uint8_t> ShadowBytes,
19301934
IRBuilder<> &IRB, Value *ShadowBase,
19311935
bool DoPoison) {
1932-
size_t n = ShadowBytes.size();
1933-
size_t i = 0;
1934-
// We need to (un)poison n bytes of stack shadow. Poison as many as we can
1935-
// using 64-bit stores (if we are on 64-bit arch), then poison the rest
1936-
// with 32-bit stores, then with 16-byte stores, then with 8-byte stores.
1937-
for (size_t LargeStoreSizeInBytes = ASan.LongSize / 8;
1938-
LargeStoreSizeInBytes != 0; LargeStoreSizeInBytes /= 2) {
1939-
for (; i + LargeStoreSizeInBytes - 1 < n; i += LargeStoreSizeInBytes) {
1940-
uint64_t Val = 0;
1941-
for (size_t j = 0; j < LargeStoreSizeInBytes; j++) {
1942-
if (F.getParent()->getDataLayout().isLittleEndian())
1936+
const size_t End = ShadowBytes.size();
1937+
1938+
const size_t LargestStoreSizeInBytes =
1939+
std::min<size_t>(sizeof(uint64_t), ASan.LongSize / 8);
1940+
1941+
const bool IsLittleEndian = F.getParent()->getDataLayout().isLittleEndian();
1942+
1943+
// Poison given range in shadow using larges store size with out leading and
1944+
// trailing zeros. Zeros never change, so they need neither poisoning nor
1945+
// up-poisoning, but we don't mind if some of them get into a middle of a
1946+
// store.
1947+
for (size_t i = 0; i < End;) {
1948+
if (!ShadowBytes[i]) {
1949+
++i;
1950+
continue;
1951+
}
1952+
1953+
size_t StoreSizeInBytes = LargestStoreSizeInBytes;
1954+
// Fit store size into the range.
1955+
while (StoreSizeInBytes > End - i)
1956+
StoreSizeInBytes /= 2;
1957+
1958+
// Minimize store size by trimming trailing zeros.
1959+
for (size_t j = StoreSizeInBytes - 1; j && !ShadowBytes[i + j]; --j) {
1960+
while (j <= StoreSizeInBytes / 2)
1961+
StoreSizeInBytes /= 2;
1962+
}
1963+
1964+
uint64_t Val = 0;
1965+
if (DoPoison) {
1966+
for (size_t j = 0; j < StoreSizeInBytes; j++) {
1967+
if (IsLittleEndian)
19431968
Val |= (uint64_t)ShadowBytes[i + j] << (8 * j);
19441969
else
19451970
Val = (Val << 8) | ShadowBytes[i + j];
19461971
}
1947-
if (!Val) continue;
1948-
Value *Ptr = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i));
1949-
Type *StoreTy = Type::getIntNTy(*C, LargeStoreSizeInBytes * 8);
1950-
Value *Poison = ConstantInt::get(StoreTy, DoPoison ? Val : 0);
1951-
IRB.CreateStore(Poison, IRB.CreateIntToPtr(Ptr, StoreTy->getPointerTo()));
1972+
assert(Val); // Impossible because ShadowBytes[i] != 0
1973+
} else {
1974+
Val = 0;
19521975
}
1976+
1977+
Value *Ptr = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i));
1978+
Value *Poison = IRB.getIntN(StoreSizeInBytes * 8, Val);
1979+
IRB.CreateStore(Poison,
1980+
IRB.CreateIntToPtr(Ptr, Poison->getType()->getPointerTo()));
1981+
1982+
i += StoreSizeInBytes;
19531983
}
19541984
}
19551985

@@ -1963,26 +1993,6 @@ static int StackMallocSizeClass(uint64_t LocalStackSize) {
19631993
llvm_unreachable("impossible LocalStackSize");
19641994
}
19651995

1966-
// Set Size bytes starting from ShadowBase to kAsanStackAfterReturnMagic.
1967-
// We can not use MemSet intrinsic because it may end up calling the actual
1968-
// memset. Size is a multiple of 8.
1969-
// Currently this generates 8-byte stores on x86_64; it may be better to
1970-
// generate wider stores.
1971-
void FunctionStackPoisoner::SetShadowToStackAfterReturnInlined(
1972-
IRBuilder<> &IRB, Value *ShadowBase, int Size) {
1973-
assert(!(Size % 8));
1974-
1975-
// kAsanStackAfterReturnMagic is 0xf5.
1976-
const uint64_t kAsanStackAfterReturnMagic64 = 0xf5f5f5f5f5f5f5f5ULL;
1977-
1978-
for (int i = 0; i < Size; i += 8) {
1979-
Value *p = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i));
1980-
IRB.CreateStore(
1981-
ConstantInt::get(IRB.getInt64Ty(), kAsanStackAfterReturnMagic64),
1982-
IRB.CreateIntToPtr(p, IRB.getInt64Ty()->getPointerTo()));
1983-
}
1984-
}
1985-
19861996
PHINode *FunctionStackPoisoner::createPHI(IRBuilder<> &IRB, Value *Cond,
19871997
Value *ValueIfTrue,
19881998
Instruction *ThenTerm,
@@ -2199,6 +2209,8 @@ void FunctionStackPoisoner::poisonStack() {
21992209
}
22002210
};
22012211

2212+
SmallVector<uint8_t, 64> ShadowBytesAfterReturn;
2213+
22022214
// (Un)poison the stack before all ret instructions.
22032215
for (auto Ret : RetVec) {
22042216
IRBuilder<> IRBRet(Ret);
@@ -2225,8 +2237,11 @@ void FunctionStackPoisoner::poisonStack() {
22252237
IRBuilder<> IRBPoison(ThenTerm);
22262238
if (StackMallocIdx <= 4) {
22272239
int ClassSize = kMinStackMallocSize << StackMallocIdx;
2228-
SetShadowToStackAfterReturnInlined(IRBPoison, ShadowBase,
2229-
ClassSize >> Mapping.Scale);
2240+
if ((int)ShadowBytesAfterReturn.size() != ClassSize) {
2241+
ShadowBytesAfterReturn.resize(ClassSize,
2242+
kAsanStackUseAfterReturnMagic);
2243+
}
2244+
poisonRedZones(ShadowBytesAfterReturn, IRBPoison, ShadowBase, true);
22302245
Value *SavedFlagPtrPtr = IRBPoison.CreateAdd(
22312246
FakeStack,
22322247
ConstantInt::get(IntptrTy, ClassSize - ASan.LongSize / 8));

test/Instrumentation/AddressSanitizer/lifetime.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,9 @@ entry:
108108
; CHECK: __asan_poison_stack_memory
109109

110110
ret void
111+
; CHECK: store i32 0
111112
; CHECK: store i64 0
112113
; CHECK: store i64 0
113-
; CHECK: store i64 0
114-
; CHECK: store i32 0
115114
; CHECK-NEXT: __asan_unpoison_stack_memory
116115
}
117116

test/Instrumentation/AddressSanitizer/stack-poisoning.ll

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ entry:
1616
; CHECK-UAR: label
1717
; CHECK-UAR: call i64 @__asan_stack_malloc_4
1818
; CHECK-UAR: label
19+
; Poison red zones.
1920
; CHECK-UAR: store i64 -1007680412564983311
2021
; CHECK-UAR: store i64 72057598113936114
21-
; CHECK-UAR: store i64 4076008178
22-
; CHECK-UAR: store i64 -868082074072645632
23-
; CHECK-UAR: store i32 -202116109
22+
; CHECK-UAR: store i32 -218959118
23+
; CHECK-UAR: store i64 -868082074056920316
24+
; CHECK-UAR: store i16 -3085
2425
; CHECK-UAR: call void @Foo
2526
; CHECK-UAR: call void @Foo
2627
; CHECK-UAR: call void @Foo
@@ -47,11 +48,11 @@ entry:
4748
; CHECK-UAR-NOT: store
4849
; CHECK-UAR: label
4950
; Else Block: no UAR frame. Only unpoison the redzones.
50-
; CHECK-UAR: store i64 0
51-
; CHECK-UAR: store i64 0
5251
; CHECK-UAR: store i64 0
5352
; CHECK-UAR: store i64 0
5453
; CHECK-UAR: store i32 0
54+
; CHECK-UAR: store i64 0
55+
; CHECK-UAR: store i16 0
5556
; CHECK-UAR-NOT: store
5657
; CHECK-UAR: label
5758
; Done, no more stores.

0 commit comments

Comments
 (0)