Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1929,27 +1929,53 @@ void FunctionStackPoisoner::poisonRedZones(ArrayRef ShadowBytes, IRBuilder<> &IRB, Value *ShadowBase, bool DoPoison) { - size_t n = ShadowBytes.size(); - size_t i = 0; - // We need to (un)poison n bytes of stack shadow. Poison as many as we can - // using 64-bit stores (if we are on 64-bit arch), then poison the rest - // with 32-bit stores, then with 16-byte stores, then with 8-byte stores. - for (size_t LargeStoreSizeInBytes = ASan.LongSize / 8; - LargeStoreSizeInBytes != 0; LargeStoreSizeInBytes /= 2) { - for (; i + LargeStoreSizeInBytes - 1 < n; i += LargeStoreSizeInBytes) { - uint64_t Val = 0; - for (size_t j = 0; j < LargeStoreSizeInBytes; j++) { - if (F.getParent()->getDataLayout().isLittleEndian()) - Val |= (uint64_t)ShadowBytes[i + j] << (8 * j); - else - Val = (Val << 8) | ShadowBytes[i + j]; - } - if (!Val) continue; - Value *Ptr = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i)); - Type *StoreTy = Type::getIntNTy(*C, LargeStoreSizeInBytes * 8); - Value *Poison = ConstantInt::get(StoreTy, DoPoison ? Val : 0); - IRB.CreateStore(Poison, IRB.CreateIntToPtr(Ptr, StoreTy->getPointerTo())); + const size_t End = ShadowBytes.size(); + + const size_t LargestStoreSizeInBytes = + std::min(sizeof(uint64_t), ASan.LongSize / 8); + + const bool IsLittleEndian = F.getParent()->getDataLayout().isLittleEndian(); + + // Poison given range in shadow using larges store size with out leading and + // 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;) { + if (!ShadowBytes[i]) { + ++i; + continue; + } + + size_t StoreSizeInBytes = LargestStoreSizeInBytes; + // Fit store size into the range. + while (StoreSizeInBytes > End - i) + StoreSizeInBytes /= 2; + + // Minimize store size by trimming trailing zeros. + for (size_t j = StoreSizeInBytes - 1; j && !ShadowBytes[i + j]; --j) { + while (j <= StoreSizeInBytes / 2) + StoreSizeInBytes /= 2; } + + uint64_t Val = 0; + for (size_t j = 0; j < StoreSizeInBytes; j++) { + if (IsLittleEndian) + Val |= (uint64_t)ShadowBytes[i + j] << (8 * j); + else + Val = (Val << 8) | ShadowBytes[i + j]; + } + + assert(Val); // Impossible because ShadowBytes[i] != 0 + + if (!DoPoison) + Val = 0; + + Value *Ptr = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i)); + Value *Poison = IRB.getIntN(StoreSizeInBytes * 8, Val); + IRB.CreateStore(Poison, + IRB.CreateIntToPtr(Ptr, Poison->getType()->getPointerTo())); + + i += StoreSizeInBytes; } } Index: test/Instrumentation/AddressSanitizer/lifetime.ll =================================================================== --- test/Instrumentation/AddressSanitizer/lifetime.ll +++ test/Instrumentation/AddressSanitizer/lifetime.ll @@ -108,10 +108,9 @@ ; CHECK: __asan_poison_stack_memory ret void + ; CHECK: store i32 0 ; CHECK: store i64 0 ; CHECK: store i64 0 - ; CHECK: store i64 0 - ; CHECK: store i32 0 ; CHECK-NEXT: __asan_unpoison_stack_memory } Index: test/Instrumentation/AddressSanitizer/stack-poisoning.ll =================================================================== --- test/Instrumentation/AddressSanitizer/stack-poisoning.ll +++ test/Instrumentation/AddressSanitizer/stack-poisoning.ll @@ -16,11 +16,12 @@ ; CHECK-UAR: label ; CHECK-UAR: call i64 @__asan_stack_malloc_4 ; CHECK-UAR: label +; Poison red zones. ; CHECK-UAR: store i64 -1007680412564983311 ; CHECK-UAR: store i64 72057598113936114 -; CHECK-UAR: store i64 4076008178 -; CHECK-UAR: store i64 -868082074072645632 -; CHECK-UAR: store i32 -202116109 +; CHECK-UAR: store i32 -218959118 +; CHECK-UAR: store i64 -868082074056920316 +; CHECK-UAR: store i16 -3085 ; CHECK-UAR: call void @Foo ; CHECK-UAR: call void @Foo ; CHECK-UAR: call void @Foo @@ -49,9 +50,9 @@ ; Else Block: no UAR frame. Only unpoison the redzones. ; CHECK-UAR: store i64 0 ; CHECK-UAR: store i64 0 - ; CHECK-UAR: store i64 0 - ; CHECK-UAR: store i64 0 ; CHECK-UAR: store i32 0 + ; CHECK-UAR: store i64 0 + ; CHECK-UAR: store i16 0 ; CHECK-UAR-NOT: store ; CHECK-UAR: label ; Done, no more stores.