-
Couldn't load subscription status.
- Fork 15k
[hwasan] Add test case for null pointer dereference #122186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This shows that HWASan will emit a memaccess intrinsic for null pointer dereferences, with or without a fixed shadow. This is a simplification of an internal bug report by dvyukov.
|
@llvm/pr-subscribers-backend-aarch64 Author: Thurston Dang (thurstond) ChangesThis shows that HWASan will emit a memaccess intrinsic for null pointer dereferences, with or without a fixed shadow. This is a simplification of an internal bug report by dvyukov. Full diff: https://github.com/llvm/llvm-project/pull/122186.diff 2 Files Affected:
diff --git a/llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll b/llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll
new file mode 100644
index 00000000000000..ee542d45cd58f5
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll
@@ -0,0 +1,130 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -filetype asm -o - %s | FileCheck %s
+
+; This shows that when dereferencing a null pointer, HWASan will call
+; __hwasan_check_x4294967071_19_fixed_0_short_v2
+; (N.B. 4294967071 == 2**32 - 239 + 14 == 2**32 - X0 + XZR
+;
+; The source was generated from llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll.
+
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android10000"
+
+$hwasan.module_ctor = comdat any
+
+$__hwasan_personality_thunk = comdat any
+
+@llvm.used = appending global [1 x ptr] [ptr @hwasan.module_ctor], section "llvm.metadata"
+@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @hwasan.module_ctor, ptr @hwasan.module_ctor }]
+@__start_hwasan_globals = external hidden constant [0 x i8]
+@__stop_hwasan_globals = external hidden constant [0 x i8]
+@hwasan.note = private constant { i32, i32, i32, [8 x i8], i32, i32 } { i32 8, i32 8, i32 3, [8 x i8] c"LLVM\00\00\00\00", i32 trunc (i64 sub (i64 ptrtoint (ptr @__start_hwasan_globals to i64), i64 ptrtoint (ptr @hwasan.note to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @__stop_hwasan_globals to i64), i64 ptrtoint (ptr @hwasan.note to i64)) to i32) }, section ".note.hwasan.globals", comdat($hwasan.module_ctor), align 4
+@hwasan.dummy.global = private constant [0 x i8] zeroinitializer, section "hwasan_globals", comdat($hwasan.module_ctor), !associated !0
+@llvm.compiler.used = appending global [2 x ptr] [ptr @hwasan.note, ptr @hwasan.dummy.global], section "llvm.metadata"
+@__hwasan_shadow = external global [0 x i8]
+
+; Function Attrs: sanitize_hwaddress
+define void @test_store_to_zeroptr() #0 {
+; CHECK-LABEL: test_store_to_zeroptr:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset w30, -16
+; CHECK-NEXT: bl __hwasan_check_x4294967071_19_fixed_0_short_v2
+; CHECK-NEXT: mov x8, xzr
+; CHECK-NEXT: mov w9, #42 // =0x2a
+; CHECK-NEXT: str x9, [x8]
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: ret
+entry:
+ %.hwasan.shadow = call ptr asm "", "=r,0"(ptr null)
+ %b = inttoptr i64 0 to ptr
+ call void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr %b, i32 19, i64 0)
+ store i64 42, ptr %b, align 8
+ ret void
+}
+
+declare void @__hwasan_init()
+
+; Function Attrs: nounwind
+define internal void @hwasan.module_ctor() #1 comdat {
+; CHECK-LABEL: hwasan.module_ctor:
+; CHECK: // %bb.0:
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: bl __hwasan_init
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: ret
+ call void @__hwasan_init()
+ ret void
+}
+
+declare i32 @__hwasan_personality_wrapper(i32, i32, i64, ptr, ptr, ptr, ptr, ptr)
+
+declare void @_Unwind_GetGR()
+
+declare void @_Unwind_GetCFA()
+
+define linkonce_odr hidden i32 @__hwasan_personality_thunk(i32 %0, i32 %1, i64 %2, ptr %3, ptr %4) comdat {
+; CHECK-LABEL: __hwasan_personality_thunk:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: adrp x6, :got:_Unwind_GetGR
+; CHECK-NEXT: adrp x7, :got:_Unwind_GetCFA
+; CHECK-NEXT: mov x5, xzr
+; CHECK-NEXT: ldr x6, [x6, :got_lo12:_Unwind_GetGR]
+; CHECK-NEXT: ldr x7, [x7, :got_lo12:_Unwind_GetCFA]
+; CHECK-NEXT: b __hwasan_personality_wrapper
+entry:
+ %5 = tail call i32 @__hwasan_personality_wrapper(i32 %0, i32 %1, i64 %2, ptr %3, ptr %4, ptr null, ptr @_Unwind_GetGR, ptr @_Unwind_GetCFA)
+ ret i32 %5
+}
+
+declare void @__hwasan_loadN(i64, i64)
+
+declare void @__hwasan_load1(i64)
+
+declare void @__hwasan_load2(i64)
+
+declare void @__hwasan_load4(i64)
+
+declare void @__hwasan_load8(i64)
+
+declare void @__hwasan_load16(i64)
+
+declare void @__hwasan_storeN(i64, i64)
+
+declare void @__hwasan_store1(i64)
+
+declare void @__hwasan_store2(i64)
+
+declare void @__hwasan_store4(i64)
+
+declare void @__hwasan_store8(i64)
+
+declare void @__hwasan_store16(i64)
+
+declare ptr @__hwasan_memmove(ptr, ptr, i64)
+
+declare ptr @__hwasan_memcpy(ptr, ptr, i64)
+
+declare ptr @__hwasan_memset(ptr, i32, i64)
+
+declare void @__hwasan_tag_memory(ptr, i8, i64)
+
+declare i8 @__hwasan_generate_tag()
+
+declare void @__hwasan_add_frame_record(i64)
+
+declare void @__hwasan_handle_vfork(i64)
+
+; Function Attrs: nounwind
+declare void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr, i32 immarg, i64 immarg) #1
+
+attributes #0 = { sanitize_hwaddress }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!1}
+
+!0 = !{ptr @hwasan.note}
+!1 = !{i32 4, !"nosanitize_hwaddress", i32 1}
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll b/llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll
new file mode 100644
index 00000000000000..a201174df995b3
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/zero-ptr.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=hwasan -S | FileCheck %s
+; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=ABORT-ZERO-BASED-SHADOW
+
+; This shows that HWASan will emit a memaccess check when dereferencing a null
+; pointer.
+; The output is used as the source for llvm/test/CodeGen/AArch64/hwasan-zero-ptr.ll.
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android10000"
+
+define void @test_store_to_zeroptr() sanitize_hwaddress {
+; CHECK-LABEL: define void @test_store_to_zeroptr
+; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr @__hwasan_shadow)
+; CHECK-NEXT: [[B:%.*]] = inttoptr i64 0 to ptr
+; CHECK-NEXT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr [[DOTHWASAN_SHADOW]], ptr [[B]], i32 19)
+; CHECK-NEXT: store i64 42, ptr [[B]], align 8
+; CHECK-NEXT: ret void
+;
+; ABORT-ZERO-BASED-SHADOW-LABEL: define void @test_store_to_zeroptr
+; ABORT-ZERO-BASED-SHADOW-SAME: () #[[ATTR0:[0-9]+]] {
+; ABORT-ZERO-BASED-SHADOW-NEXT: entry:
+; ABORT-ZERO-BASED-SHADOW-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr null)
+; ABORT-ZERO-BASED-SHADOW-NEXT: [[B:%.*]] = inttoptr i64 0 to ptr
+; ABORT-ZERO-BASED-SHADOW-NEXT: call void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr [[B]], i32 19, i64 0)
+; ABORT-ZERO-BASED-SHADOW-NEXT: store i64 42, ptr [[B]], align 8
+; ABORT-ZERO-BASED-SHADOW-NEXT: ret void
+;
+entry:
+ %b = inttoptr i64 0 to i64*
+ store i64 42, ptr %b
+ ret void
+}
|
|
|
||
| declare void @__hwasan_load2(i64) | ||
|
|
||
| declare void @__hwasan_load4(i64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of unneeded declarations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pruned
If the pointer to be checked is statically known to be zero, the tag check will pass since: 1) the tag is zero 2) shadow memory for address 0 is initialized to 0. We therefore elide the check when lowering. This also updates the test in llvm#122186 Note: the HWASan instrumentation pass will still emit the check.memaccess intrinsic. This patch performs the elision at CodeGen.
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/3/builds/10072 Here is the relevant piece of the build log for the reference |
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 #122186
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/llvm-project#122186
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
This shows that HWASan will emit a memaccess intrinsic for null pointer dereferences, with or without a fixed shadow.
This is a simplification of an internal bug report by dvyukov.