Skip to content

Commit 1e2243e

Browse files
thurstondBaiXilin
authored andcommitted
[hwasan] Omit tag check for null pointers (llvm#122206)
If the pointer to be checked is statically known to be zero, the tag check will always pass since: 1) the tag is zero 2) shadow memory for address 0 is initialized to 0 and never updated. We can therefore elide the tag check. We perform the elision in two places: 1) the HWASan pass 2) when lowering the CHECK_MEMACCESS intrinsic. Conceivably, the HWASan pass may encounter a "cannot currently statically prove to be null" pointer (and is therefore unable to omit the intrinsic) that later optimization passes convert into a statically known-null pointer. As a last line of defense, we perform elision here too. This also updates the tests from llvm#122186
1 parent 0730df4 commit 1e2243e

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,15 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
605605

606606
void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
607607
Register Reg = MI.getOperand(0).getReg();
608+
609+
// The HWASan pass won't emit a CHECK_MEMACCESS intrinsic with a pointer
610+
// statically known to be zero. However, conceivably, the HWASan pass may
611+
// encounter a "cannot currently statically prove to be null" pointer (and is
612+
// therefore unable to omit the intrinsic) that later optimization passes
613+
// convert into a statically known-null pointer.
614+
if (Reg == AArch64::XZR)
615+
return;
616+
608617
bool IsShort =
609618
((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
610619
(MI.getOpcode() ==

llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ class HWAddressSanitizer {
348348
bool ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE, MemIntrinsic *MI);
349349
void instrumentMemIntrinsic(MemIntrinsic *MI);
350350
bool instrumentMemAccess(InterestingMemoryOperand &O, DomTreeUpdater &DTU,
351-
LoopInfo *LI);
351+
LoopInfo *LI, const DataLayout &DL);
352352
bool ignoreAccessWithoutRemark(Instruction *Inst, Value *Ptr);
353353
bool ignoreAccess(OptimizationRemarkEmitter &ORE, Instruction *Inst,
354354
Value *Ptr);
@@ -1163,12 +1163,23 @@ void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
11631163
}
11641164

11651165
bool HWAddressSanitizer::instrumentMemAccess(InterestingMemoryOperand &O,
1166-
DomTreeUpdater &DTU,
1167-
LoopInfo *LI) {
1166+
DomTreeUpdater &DTU, LoopInfo *LI,
1167+
const DataLayout &DL) {
11681168
Value *Addr = O.getPtr();
11691169

11701170
LLVM_DEBUG(dbgs() << "Instrumenting: " << O.getInsn() << "\n");
11711171

1172+
// If the pointer is statically known to be zero, the tag check will pass
1173+
// since:
1174+
// 1) it has a zero tag
1175+
// 2) the shadow memory corresponding to address 0 is initialized to zero and
1176+
// never updated.
1177+
// We can therefore elide the tag check.
1178+
llvm::KnownBits Known(DL.getPointerTypeSizeInBits(Addr->getType()));
1179+
llvm::computeKnownBits(Addr, Known, DL);
1180+
if (Known.isZero())
1181+
return false;
1182+
11721183
if (O.MaybeMask)
11731184
return false; // FIXME
11741185

@@ -1701,8 +1712,9 @@ void HWAddressSanitizer::sanitizeFunction(Function &F,
17011712
PostDominatorTree *PDT = FAM.getCachedResult<PostDominatorTreeAnalysis>(F);
17021713
LoopInfo *LI = FAM.getCachedResult<LoopAnalysis>(F);
17031714
DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
1715+
const DataLayout &DL = F.getDataLayout();
17041716
for (auto &Operand : OperandsToInstrument)
1705-
instrumentMemAccess(Operand, DTU, LI);
1717+
instrumentMemAccess(Operand, DTU, LI, DL);
17061718
DTU.flush();
17071719

17081720
if (ClInstrumentMemIntrinsics && !IntrinToInstrument.empty()) {

llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
22
; RUN: llc -filetype asm -o - %s | FileCheck %s
33

4-
; This shows that when dereferencing a null pointer, HWASan will call
5-
; __hwasan_check_x4294967071_19_fixed_0_short_v2
6-
; (N.B. 4294967071 == 2**32 - 239 + 14 == 2**32 - X0 + XZR
4+
; This shows that CodeGen for AArch64 will elide the tag check when lowering
5+
; the HWASan memaccess intrinsic for null pointers.
76
;
8-
; The source was generated from llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll.
7+
; N.B. The HWASan pass will normally omit the memaccess intrinsic if the
8+
; pointer is already statically known to be null.
9+
;
10+
; The source was generated from llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll
11+
; with the memaccess deliberately retained.
912

1013
; ModuleID = '<stdin>'
1114
source_filename = "<stdin>"
@@ -25,7 +28,6 @@ define void @test_store_to_zeroptr() #0 {
2528
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
2629
; CHECK-NEXT: .cfi_def_cfa_offset 16
2730
; CHECK-NEXT: .cfi_offset w30, -16
28-
; CHECK-NEXT: bl __hwasan_check_x4294967071_19_fixed_0_short_v2
2931
; CHECK-NEXT: mov x8, xzr
3032
; CHECK-NEXT: mov w9, #42 // =0x2a
3133
; CHECK-NEXT: str x9, [x8]

llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: opt < %s -passes=hwasan -S | FileCheck %s
33
; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=ABORT-ZERO-BASED-SHADOW
44

5-
; This shows that HWASan will emit a memaccess check when dereferencing a null
5+
; This shows that HWASan omits the memaccess check when dereferencing a null
66
; pointer.
77
; The output is used as the source for llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll.
88

@@ -15,7 +15,6 @@ define void @test_store_to_zeroptr() sanitize_hwaddress {
1515
; CHECK-NEXT: entry:
1616
; CHECK-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr @__hwasan_shadow)
1717
; CHECK-NEXT: [[B:%.*]] = inttoptr i64 0 to ptr
18-
; CHECK-NEXT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr [[DOTHWASAN_SHADOW]], ptr [[B]], i32 19)
1918
; CHECK-NEXT: store i64 42, ptr [[B]], align 8
2019
; CHECK-NEXT: ret void
2120
;
@@ -24,7 +23,6 @@ define void @test_store_to_zeroptr() sanitize_hwaddress {
2423
; ABORT-ZERO-BASED-SHADOW-NEXT: entry:
2524
; ABORT-ZERO-BASED-SHADOW-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr null)
2625
; ABORT-ZERO-BASED-SHADOW-NEXT: [[B:%.*]] = inttoptr i64 0 to ptr
27-
; ABORT-ZERO-BASED-SHADOW-NEXT: call void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr [[B]], i32 19, i64 0)
2826
; ABORT-ZERO-BASED-SHADOW-NEXT: store i64 42, ptr [[B]], align 8
2927
; ABORT-ZERO-BASED-SHADOW-NEXT: ret void
3028
;

0 commit comments

Comments
 (0)