summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
authorJulian Lettner <jlettner@apple.com>2019-01-24 01:06:19 +0000
committerJulian Lettner <jlettner@apple.com>2019-01-24 01:06:19 +0000
commitcea84ab93aeb079a358ab1c8aeba6d9140ef8b47 (patch)
tree3c059cf1dbc208d26fc1df2547d0a18e18448095 /llvm/test
parent970d9d9acc421cc43fa801d2be81328d066200ec (diff)
downloadbcm5719-llvm-cea84ab93aeb079a358ab1c8aeba6d9140ef8b47.tar.gz
bcm5719-llvm-cea84ab93aeb079a358ab1c8aeba6d9140ef8b47.zip
[Sanitizers] UBSan unreachable incompatible with ASan in the presence of `noreturn` calls
Summary: UBSan wants to detect when unreachable code is actually reached, so it adds instrumentation before every `unreachable` instruction. However, the optimizer will remove code after calls to functions marked with `noreturn`. To avoid this UBSan removes `noreturn` from both the call instruction as well as from the function itself. Unfortunately, ASan relies on this annotation to unpoison the stack by inserting calls to `_asan_handle_no_return` before `noreturn` functions. This is important for functions that do not return but access the the stack memory, e.g., unwinder functions *like* `longjmp` (`longjmp` itself is actually "double-proofed" via its interceptor). The result is that when ASan and UBSan are combined, the `noreturn` attributes are missing and ASan cannot unpoison the stack, so it has false positives when stack unwinding is used. Changes: # UBSan now adds the `expect_noreturn` attribute whenever it removes the `noreturn` attribute from a function # ASan additionally checks for the presence of this attribute Generated code: ``` call void @__asan_handle_no_return // Additionally inserted to avoid false positives call void @longjmp call void @__asan_handle_no_return call void @__ubsan_handle_builtin_unreachable unreachable ``` The second call to `__asan_handle_no_return` is redundant. This will be cleaned up in a follow-up patch. rdar://problem/40723397 Reviewers: delcypher, eugenis Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D56624 llvm-svn: 352003
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/Bitcode/attributes.ll11
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/instrument-no-return.ll48
2 files changed, 37 insertions, 22 deletions
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index de3cf8dd4d7..e96007e5629 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -204,7 +204,7 @@ define void @f34()
; CHECK: define void @f34()
{
call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #36
+; CHECK: call void @nobuiltin() #37
ret void;
}
@@ -351,6 +351,12 @@ define void @f59() shadowcallstack
ret void
}
+; CHECK: define void @f60() #36
+define void @f60() expect_noreturn
+{
+ ret void
+}
+
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
@@ -387,4 +393,5 @@ define void @f59() shadowcallstack
; CHECK: attributes #33 = { speculatable }
; CHECK: attributes #34 = { sanitize_hwaddress }
; CHECK: attributes #35 = { shadowcallstack }
-; CHECK: attributes #36 = { nobuiltin }
+; CHECK: attributes #36 = { expect_noreturn }
+; CHECK: attributes #37 = { nobuiltin }
diff --git a/llvm/test/Instrumentation/AddressSanitizer/instrument-no-return.ll b/llvm/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
index 2e90bfc64b2..b8e6aef9848 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
@@ -1,37 +1,45 @@
-; RUN: opt < %s -asan -asan-module -S | FileCheck %s
+; RUN: opt < %s -asan -S | FileCheck %s
; AddressSanitizer must insert __asan_handle_no_return
; before every noreturn call or invoke.
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
-declare void @MyNoReturnFunc(i32) noreturn
+declare void @NormalFunc()
+declare void @NoReturnFunc() noreturn
-define i32 @Call1(i8* nocapture %arg) uwtable sanitize_address {
-entry:
- call void @MyNoReturnFunc(i32 1) noreturn ; The call insn has noreturn attr.
-; CHECK: @Call1
-; CHECK: call void @__asan_handle_no_return
-; CHECK-NEXT: call void @MyNoReturnFunc
-; CHECK-NEXT: unreachable
+; Instrument calls to noreturn functions (regardless of callsite)
+define i32 @Call1() sanitize_address {
+ call void @NoReturnFunc()
unreachable
}
-
-define i32 @Call2(i8* nocapture %arg) uwtable sanitize_address {
-entry:
- call void @MyNoReturnFunc(i32 1) ; No noreturn attribure on the call.
-; CHECK: @Call2
+; CHECK-LABEL: @Call1
; CHECK: call void @__asan_handle_no_return
-; CHECK-NEXT: call void @MyNoReturnFunc
-; CHECK-NEXT: unreachable
+; CHECK-NEXT: call void @NoReturnFunc
+
+; Instrument noreturn call sites (regardless of function)
+define i32 @Call2() sanitize_address {
+ call void @NormalFunc() noreturn
unreachable
}
+; CHECK-LABEL: @Call2
+; CHECK: call void @__asan_handle_no_return
+; CHECK-NEXT: call void @NormalFunc
+
+; Also instrument expect_noreturn call sites
+define i32 @Call3() sanitize_address {
+ call void @NormalFunc() expect_noreturn
+ ret i32 0
+}
+; CHECK-LABEL: @Call3
+; CHECK: call void @__asan_handle_no_return
+; CHECK-NEXT: call void @NormalFunc
declare i32 @__gxx_personality_v0(...)
-define i64 @Invoke1(i8** %esc) nounwind uwtable ssp sanitize_address personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+define i64 @Invoke1(i8** %esc) sanitize_address personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
- invoke void @MyNoReturnFunc(i32 1)
+ invoke void @NoReturnFunc()
to label %invoke.cont unwind label %lpad
invoke.cont:
@@ -42,8 +50,8 @@ lpad:
filter [0 x i8*] zeroinitializer
ret i64 1
}
-; CHECK: @Invoke1
+; CHECK-LABEL: @Invoke1
; CHECK: call void @__asan_handle_no_return
-; CHECK-NEXT: invoke void @MyNoReturnFunc
+; CHECK-NEXT: invoke void @NoReturnFunc
; CHECK: ret i64 0
; CHECK: ret i64 1
OpenPOWER on IntegriCloud