Skip to content

Commit 644422a

Browse files
committed
hwasan: Use bits [3..11) of the ring buffer entry address as the base stack tag.
This saves roughly 32 bytes of instructions per function with stack objects and causes us to preserve enough information that we can recover the original tags of all stack variables. Now that stack tags are deterministic, we no longer need to pass -hwasan-generate-tags-with-calls during check-hwasan. This also means that the new stack tag generation mechanism is exercised by check-hwasan. Differential Revision: https://reviews.llvm.org/D63360 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363636 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f159a11 commit 644422a

File tree

3 files changed

+41
-24
lines changed

3 files changed

+41
-24
lines changed

lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class HWAddressSanitizer {
218218
Value *getUARTag(IRBuilder<> &IRB, Value *StackTag);
219219

220220
Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty);
221-
Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
221+
void emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
222222

223223
private:
224224
LLVMContext *C;
@@ -284,6 +284,7 @@ class HWAddressSanitizer {
284284
Constant *ShadowGlobal;
285285

286286
Value *LocalDynamicShadow = nullptr;
287+
Value *StackBaseTag = nullptr;
287288
GlobalValue *ThreadPtrGlobal = nullptr;
288289
};
289290

@@ -750,10 +751,16 @@ static unsigned RetagMask(unsigned AllocaNo) {
750751
// x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
751752
// masks.
752753
// The list does not include the value 255, which is used for UAR.
753-
static unsigned FastMasks[] = {
754-
0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
755-
28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
756-
124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
754+
//
755+
// Because we are more likely to use earlier elements of this list than later
756+
// ones, it is sorted in increasing order of probability of collision with a
757+
// mask allocated (temporally) nearby. The program that generated this list
758+
// can be found at:
759+
// https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/sort_masks.py
760+
static unsigned FastMasks[] = {0, 128, 64, 192, 32, 96, 224, 112, 240,
761+
48, 16, 120, 248, 56, 24, 8, 124, 252,
762+
60, 28, 12, 4, 126, 254, 62, 30, 14,
763+
6, 2, 127, 63, 31, 15, 7, 3, 1};
757764
return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
758765
}
759766

@@ -764,6 +771,8 @@ Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
764771
Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
765772
if (ClGenerateTagsWithCalls)
766773
return getNextTagWithCall(IRB);
774+
if (StackBaseTag)
775+
return StackBaseTag;
767776
// FIXME: use addressofreturnaddress (but implement it in aarch64 backend
768777
// first).
769778
Module *M = IRB.GetInsertBlock()->getParent()->getParent();
@@ -881,13 +890,16 @@ void HWAddressSanitizer::createFrameGlobal(Function &F,
881890
GV->setComdat(Comdat);
882891
}
883892

884-
Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
885-
bool WithFrameRecord) {
886-
if (!Mapping.InTls)
887-
return getDynamicShadowNonTls(IRB);
893+
void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) {
894+
if (!Mapping.InTls) {
895+
LocalDynamicShadow = getDynamicShadowNonTls(IRB);
896+
return;
897+
}
888898

889-
if (!WithFrameRecord && TargetTriple.isAndroid())
890-
return getDynamicShadowIfunc(IRB);
899+
if (!WithFrameRecord && TargetTriple.isAndroid()) {
900+
LocalDynamicShadow = getDynamicShadowIfunc(IRB);
901+
return;
902+
}
891903

892904
Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
893905
assert(SlotPtr);
@@ -920,6 +932,8 @@ Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
920932
TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong);
921933

922934
if (WithFrameRecord) {
935+
StackBaseTag = IRB.CreateAShr(ThreadLong, 3);
936+
923937
// Prepare ring buffer data.
924938
auto PC = IRB.CreatePtrToInt(F, IntptrTy);
925939
auto GetStackPointerFn =
@@ -928,7 +942,7 @@ Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
928942
IRB.CreateCall(GetStackPointerFn,
929943
{Constant::getNullValue(IRB.getInt32Ty())}),
930944
IntptrTy);
931-
// Mix SP and PC. TODO: also add the tag to the mix.
945+
// Mix SP and PC.
932946
// Assumptions:
933947
// PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
934948
// SP is 0xsssssssssssSSSS0 (4 lower bits are zero)
@@ -959,13 +973,12 @@ Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
959973
// Get shadow base address by aligning RecordPtr up.
960974
// Note: this is not correct if the pointer is already aligned.
961975
// Runtime library will make sure this never happens.
962-
Value *ShadowBase = IRB.CreateAdd(
976+
LocalDynamicShadow = IRB.CreateAdd(
963977
IRB.CreateOr(
964978
ThreadLongMaybeUntagged,
965979
ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
966980
ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
967-
ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy);
968-
return ShadowBase;
981+
LocalDynamicShadow = IRB.CreateIntToPtr(LocalDynamicShadow, Int8PtrTy);
969982
}
970983

971984
bool HWAddressSanitizer::instrumentLandingPads(
@@ -1115,9 +1128,9 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
11151128

11161129
Instruction *InsertPt = &*F.getEntryBlock().begin();
11171130
IRBuilder<> EntryIRB(InsertPt);
1118-
LocalDynamicShadow = emitPrologue(EntryIRB,
1119-
/*WithFrameRecord*/ ClRecordStackHistory &&
1120-
!AllocasToInstrument.empty());
1131+
emitPrologue(EntryIRB,
1132+
/*WithFrameRecord*/ ClRecordStackHistory &&
1133+
!AllocasToInstrument.empty());
11211134

11221135
bool Changed = false;
11231136
if (!AllocasToInstrument.empty()) {
@@ -1146,6 +1159,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
11461159
Changed |= instrumentMemAccess(Inst);
11471160

11481161
LocalDynamicShadow = nullptr;
1162+
StackBaseTag = nullptr;
11491163

11501164
return Changed;
11511165
}

test/Instrumentation/HWAddressSanitizer/dbg-declare-tag-offset.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ entry:
1313
%nodebug3 = alloca i8*
1414
%a = alloca i8*
1515
%b = alloca i8*
16-
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 4)
16+
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 32)
1717
call void @llvm.dbg.declare(metadata i8** %a, metadata !12, metadata !DIExpression()), !dbg !14
18-
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 4)
18+
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 32)
1919
call void @llvm.dbg.declare(metadata i8** %a, metadata !12, metadata !DIExpression()), !dbg !14
20-
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 6)
20+
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 96)
2121
call void @llvm.dbg.declare(metadata i8** %b, metadata !13, metadata !DIExpression()), !dbg !14
22-
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 6)
22+
; CHECK: @llvm.dbg.declare{{.*}} !DIExpression(DW_OP_LLVM_tag_offset, 96)
2323
call void @llvm.dbg.declare(metadata i8** %b, metadata !13, metadata !DIExpression()), !dbg !14
2424
call void @g(i8** %nodebug0, i8** %nodebug1, i8** %nodebug2, i8** %nodebug3, i8** %a, i8** %b)
2525
ret void, !dbg !15

test/Instrumentation/HWAddressSanitizer/prologue.ll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ define void @test_alloca() sanitize_hwaddress {
5656
; CHECK-TLS: %[[B:[^ ]*]] = getelementptr i8, i8* %[[A]], i32 48
5757
; CHECK-TLS: %[[C:[^ ]*]] = bitcast i8* %[[B]] to i64*
5858
; CHECK-TLS: %[[D:[^ ]*]] = load i64, i64* %[[C]]
59+
; CHECK-TLS: %[[E:[^ ]*]] = ashr i64 %[[D]], 3
5960

6061
; CHECK-NOHISTORY-NOT: store i64
6162

@@ -68,8 +69,10 @@ define void @test_alloca() sanitize_hwaddress {
6869
; CHECK-HISTORY: %[[D5:[^ ]*]] = and i64 %[[D4]], %[[D3]]
6970
; CHECK-HISTORY: store i64 %[[D5]], i64* %[[C]]
7071

71-
; CHECK-TLS: %[[E:[^ ]*]] = or i64 %[[D]], 4294967295
72-
; CHECK-TLS: = add i64 %[[E]], 1
72+
; CHECK-TLS: %[[F:[^ ]*]] = or i64 %[[D]], 4294967295
73+
; CHECK-TLS: = add i64 %[[F]], 1
74+
75+
; CHECK-HISTORY: = xor i64 %[[E]], 0
7376

7477
; CHECK-NOHISTORY-NOT: store i64
7578

0 commit comments

Comments
 (0)