diff --git a/compiler-rt/test/hwasan/TestCases/longjmp.c b/compiler-rt/test/hwasan/TestCases/longjmp.c --- a/compiler-rt/test/hwasan/TestCases/longjmp.c +++ b/compiler-rt/test/hwasan/TestCases/longjmp.c @@ -6,6 +6,7 @@ #include #include #include +#include "utils.h" __attribute__((noinline)) int f(void *caller_frame) { @@ -21,6 +22,8 @@ } int main() { + bump_tag(); + return f(__builtin_frame_address(0)); // CHECK: READ of size 8 at {{.*}} tags: {{.*}}/00 (ptr/mem) } diff --git a/compiler-rt/test/hwasan/TestCases/mem-intrinsics.c b/compiler-rt/test/hwasan/TestCases/mem-intrinsics.c --- a/compiler-rt/test/hwasan/TestCases/mem-intrinsics.c +++ b/compiler-rt/test/hwasan/TestCases/mem-intrinsics.c @@ -8,8 +8,9 @@ #include #include #include +#include "utils.h" -int main() { +void f() { char Q[16] __attribute__((aligned(256))); char P[16] __attribute__((aligned(256))); #if TEST_NO == 1 @@ -35,5 +36,9 @@ // READ-NOT: recovered // RECOVER: recovered - return 0; +} + +int main() { + bump_tag(); + f(); } diff --git a/compiler-rt/test/hwasan/TestCases/stack-history-length.c b/compiler-rt/test/hwasan/TestCases/stack-history-length.c --- a/compiler-rt/test/hwasan/TestCases/stack-history-length.c +++ b/compiler-rt/test/hwasan/TestCases/stack-history-length.c @@ -5,6 +5,7 @@ // REQUIRES: stable-runtime #include +#include "utils.h" void USE(void *x) { // pretend_to_do_something(void *x) __asm__ __volatile__("" : : "r" (x) : "memory"); @@ -16,6 +17,8 @@ __attribute__((noinline)) void OOB() { int x[4]; x[four] = 0; USE(&x[0]); } int main(int argc, char **argv) { + bump_tag(); + int X = argc == 2 ? atoi(argv[1]) : 10; // FUNC0 is X+2's element of the ring buffer. // If runtime buffer size is less than it, FUNC0 record will be lost. diff --git a/compiler-rt/test/hwasan/TestCases/stack-oob.c b/compiler-rt/test/hwasan/TestCases/stack-oob.c --- a/compiler-rt/test/hwasan/TestCases/stack-oob.c +++ b/compiler-rt/test/hwasan/TestCases/stack-oob.c @@ -6,6 +6,7 @@ #include #include +#include "utils.h" __attribute__((noinline)) int f() { @@ -15,9 +16,11 @@ } int main() { + bump_tag(); + return f(); // CHECK: READ of size 1 at - // CHECK: #0 {{.*}} in f{{.*}}stack-oob.c:14 + // CHECK: #0 {{.*}} in f{{.*}}stack-oob.c:15 // CHECK: is located in stack of threa diff --git a/compiler-rt/test/hwasan/TestCases/stack-uar.c b/compiler-rt/test/hwasan/TestCases/stack-uar.c --- a/compiler-rt/test/hwasan/TestCases/stack-uar.c +++ b/compiler-rt/test/hwasan/TestCases/stack-uar.c @@ -4,6 +4,8 @@ // REQUIRES: stable-runtime +#include "utils.h" + void USE(void *x) { // pretend_to_do_something(void *x) __asm__ __volatile__("" : : "r" (x) : "memory"); } @@ -20,6 +22,8 @@ __attribute__((noinline)) void Unrelated3() { int CCC[4]; USE(&CCC[0]); } int main() { + bump_tag(); + char *p = buggy(); Unrelated1(); Unrelated2(); diff --git a/compiler-rt/test/hwasan/TestCases/utils.h b/compiler-rt/test/hwasan/TestCases/utils.h new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/utils.h @@ -0,0 +1,10 @@ +__attribute__((noinline)) void bump_tag1() { + volatile char x[64]; + x[0] = 0; +} + +// Create 128 ring buffer entries to bump the base tag to 128. +void bump_tag() { + for (int i = 0; i != 128; ++i) + bump_tag1(); +} diff --git a/compiler-rt/test/hwasan/lit.cfg b/compiler-rt/test/hwasan/lit.cfg --- a/compiler-rt/test/hwasan/lit.cfg +++ b/compiler-rt/test/hwasan/lit.cfg @@ -11,7 +11,7 @@ # Setup default compiler flags used with -fsanitize=memory option. clang_cflags = [config.target_cflags] + config.debug_info_flags clang_cxxflags = config.cxx_mode_flags + clang_cflags -clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls"] + clang_cflags +clang_hwasan_cflags = ["-fsanitize=hwaddress"] + clang_cflags clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags def build_invocation(compile_flags): diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -218,7 +218,7 @@ Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty); - Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord); + void emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord); private: LLVMContext *C; @@ -284,6 +284,7 @@ Constant *ShadowGlobal; Value *LocalDynamicShadow = nullptr; + Value *StackBaseTag = nullptr; GlobalValue *ThreadPtrGlobal = nullptr; }; @@ -764,6 +765,8 @@ Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { if (ClGenerateTagsWithCalls) return getNextTagWithCall(IRB); + if (StackBaseTag) + return StackBaseTag; // FIXME: use addressofreturnaddress (but implement it in aarch64 backend // first). Module *M = IRB.GetInsertBlock()->getParent()->getParent(); @@ -881,13 +884,16 @@ GV->setComdat(Comdat); } -Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, - bool WithFrameRecord) { - if (!Mapping.InTls) - return getDynamicShadowNonTls(IRB); +void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { + if (!Mapping.InTls) { + LocalDynamicShadow = getDynamicShadowNonTls(IRB); + return; + } - if (!WithFrameRecord && TargetTriple.isAndroid()) - return getDynamicShadowIfunc(IRB); + if (!WithFrameRecord && TargetTriple.isAndroid()) { + LocalDynamicShadow = getDynamicShadowIfunc(IRB); + return; + } Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy); assert(SlotPtr); @@ -920,6 +926,8 @@ TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong); if (WithFrameRecord) { + StackBaseTag = IRB.CreateAShr(ThreadLong, 3); + // Prepare ring buffer data. auto PC = IRB.CreatePtrToInt(F, IntptrTy); auto GetStackPointerFn = @@ -928,7 +936,7 @@ IRB.CreateCall(GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())}), IntptrTy); - // Mix SP and PC. TODO: also add the tag to the mix. + // Mix SP and PC. // Assumptions: // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero) // SP is 0xsssssssssssSSSS0 (4 lower bits are zero) @@ -959,13 +967,12 @@ // Get shadow base address by aligning RecordPtr up. // Note: this is not correct if the pointer is already aligned. // Runtime library will make sure this never happens. - Value *ShadowBase = IRB.CreateAdd( + LocalDynamicShadow = IRB.CreateAdd( IRB.CreateOr( ThreadLongMaybeUntagged, ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)), ConstantInt::get(IntptrTy, 1), "hwasan.shadow"); - ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy); - return ShadowBase; + LocalDynamicShadow = IRB.CreateIntToPtr(LocalDynamicShadow, Int8PtrTy); } bool HWAddressSanitizer::instrumentLandingPads( @@ -1115,9 +1122,9 @@ Instruction *InsertPt = &*F.getEntryBlock().begin(); IRBuilder<> EntryIRB(InsertPt); - LocalDynamicShadow = emitPrologue(EntryIRB, - /*WithFrameRecord*/ ClRecordStackHistory && - !AllocasToInstrument.empty()); + emitPrologue(EntryIRB, + /*WithFrameRecord*/ ClRecordStackHistory && + !AllocasToInstrument.empty()); bool Changed = false; if (!AllocasToInstrument.empty()) { @@ -1146,6 +1153,7 @@ Changed |= instrumentMemAccess(Inst); LocalDynamicShadow = nullptr; + StackBaseTag = nullptr; return Changed; } diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll b/llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll --- a/llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll +++ b/llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll @@ -56,6 +56,7 @@ ; CHECK-TLS: %[[B:[^ ]*]] = getelementptr i8, i8* %[[A]], i32 48 ; CHECK-TLS: %[[C:[^ ]*]] = bitcast i8* %[[B]] to i64* ; CHECK-TLS: %[[D:[^ ]*]] = load i64, i64* %[[C]] +; CHECK-TLS: %[[E:[^ ]*]] = ashr i64 %[[D]], 3 ; CHECK-NOHISTORY-NOT: store i64 @@ -68,8 +69,10 @@ ; CHECK-HISTORY: %[[D5:[^ ]*]] = and i64 %[[D4]], %[[D3]] ; CHECK-HISTORY: store i64 %[[D5]], i64* %[[C]] -; CHECK-TLS: %[[E:[^ ]*]] = or i64 %[[D]], 4294967295 -; CHECK-TLS: = add i64 %[[E]], 1 +; CHECK-TLS: %[[F:[^ ]*]] = or i64 %[[D]], 4294967295 +; CHECK-TLS: = add i64 %[[F]], 1 + +; CHECK-HISTORY: = xor i64 %[[E]], 0 ; CHECK-NOHISTORY-NOT: store i64