diff options
Diffstat (limited to 'test/Instrumentation')
21 files changed, 1358 insertions, 53 deletions
diff --git a/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll b/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll index 35c5c4a0bba4e..38168fc2d68da 100644 --- a/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll +++ b/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll @@ -36,14 +36,14 @@ target triple = "i386-unknown-linux-gnu" @ff_mlp_firorder_7 = external global i8 @ff_mlp_firorder_8 = external global i8 -define void @ff_mlp_init_x86(%struct.DSPContext* nocapture %c, %struct.AVCodecContext* nocapture %avctx) nounwind address_safety { +define void @ff_mlp_init_x86(%struct.DSPContext* nocapture %c, %struct.AVCodecContext* nocapture %avctx) nounwind sanitize_address { entry: %mlp_filter_channel = getelementptr inbounds %struct.DSPContext* %c, i32 0, i32 131 store void (i32*, i32*, i32, i32, i32, i32, i32, i32*)* @mlp_filter_channel_x86, void (i32*, i32*, i32, i32, i32, i32, i32, i32*)** %mlp_filter_channel, align 4, !tbaa !0 ret void } -define internal void @mlp_filter_channel_x86(i32* %state, i32* %coeff, i32 %firorder, i32 %iirorder, i32 %filter_shift, i32 %mask, i32 %blocksize, i32* %sample_buffer) nounwind address_safety { +define internal void @mlp_filter_channel_x86(i32* %state, i32* %coeff, i32 %firorder, i32 %iirorder, i32 %filter_shift, i32 %mask, i32 %blocksize, i32* %sample_buffer) nounwind sanitize_address { entry: %filter_shift.addr = alloca i32, align 4 %mask.addr = alloca i32, align 4 diff --git a/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll b/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll new file mode 100644 index 0000000000000..6a60d1c29f564 --- /dev/null +++ b/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll @@ -0,0 +1,57 @@ +; RUN: opt < %s -asan -asan-module -S | FileCheck %s +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" + +; Here we check that the global redzone sizes grow with the object size. + +@G10 = global [10 x i8] zeroinitializer, align 1 +; CHECK: @G10 = global { [10 x i8], [54 x i8] } + +@G31 = global [31 x i8] zeroinitializer, align 1 +@G32 = global [32 x i8] zeroinitializer, align 1 +@G33 = global [33 x i8] zeroinitializer, align 1 +; CHECK: @G31 = global { [31 x i8], [33 x i8] } +; CHECK: @G32 = global { [32 x i8], [32 x i8] } +; CHECK: @G33 = global { [33 x i8], [63 x i8] } + +@G63 = global [63 x i8] zeroinitializer, align 1 +@G64 = global [64 x i8] zeroinitializer, align 1 +@G65 = global [65 x i8] zeroinitializer, align 1 +; CHECK: @G63 = global { [63 x i8], [33 x i8] } +; CHECK: @G64 = global { [64 x i8], [32 x i8] } +; CHECK: @G65 = global { [65 x i8], [63 x i8] } + +@G127 = global [127 x i8] zeroinitializer, align 1 +@G128 = global [128 x i8] zeroinitializer, align 1 +@G129 = global [129 x i8] zeroinitializer, align 1 +; CHECK: @G127 = global { [127 x i8], [33 x i8] } +; CHECK: @G128 = global { [128 x i8], [32 x i8] } +; CHECK: @G129 = global { [129 x i8], [63 x i8] } + +@G255 = global [255 x i8] zeroinitializer, align 1 +@G256 = global [256 x i8] zeroinitializer, align 1 +@G257 = global [257 x i8] zeroinitializer, align 1 +; CHECK: @G255 = global { [255 x i8], [33 x i8] } +; CHECK: @G256 = global { [256 x i8], [64 x i8] } +; CHECK: @G257 = global { [257 x i8], [95 x i8] } + +@G511 = global [511 x i8] zeroinitializer, align 1 +@G512 = global [512 x i8] zeroinitializer, align 1 +@G513 = global [513 x i8] zeroinitializer, align 1 +; CHECK: @G511 = global { [511 x i8], [97 x i8] } +; CHECK: @G512 = global { [512 x i8], [128 x i8] } +; CHECK: @G513 = global { [513 x i8], [159 x i8] } + +@G1023 = global [1023 x i8] zeroinitializer, align 1 +@G1024 = global [1024 x i8] zeroinitializer, align 1 +@G1025 = global [1025 x i8] zeroinitializer, align 1 +; CHECK: @G1023 = global { [1023 x i8], [225 x i8] } +; CHECK: @G1024 = global { [1024 x i8], [256 x i8] } +; CHECK: @G1025 = global { [1025 x i8], [287 x i8] } + +@G1000000 = global [1000000 x i8] zeroinitializer, align 1 +@G10000000 = global [10000000 x i8] zeroinitializer, align 1 +@G100000000 = global [100000000 x i8] zeroinitializer, align 1 +; CHECK: @G1000000 = global { [1000000 x i8], [249984 x i8] } +; CHECK: @G10000000 = global { [10000000 x i8], [262144 x i8] } +; CHECK: @G100000000 = global { [100000000 x i8], [262144 x i8] } diff --git a/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll b/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll index c0fe15e9fcecb..da8f54137598e 100644 --- a/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll +++ b/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll @@ -11,9 +11,9 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3 @f = global %struct_of_7_bytes_4_aligned zeroinitializer, align 4 -; Accessing bytes 4 and 6, not ok to widen to i32 if address_safety is set. +; Accessing bytes 4 and 6, not ok to widen to i32 if sanitize_address is set. -define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone address_safety { +define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone sanitize_address { entry: %tmp = load i8* getelementptr inbounds (%struct_of_7_bytes_4_aligned* @f, i64 0, i32 1), align 4 %conv = zext i8 %tmp to i32 @@ -36,7 +36,7 @@ define void @end_test_widening_bad() { ;; Accessing bytes 4 and 5. Ok to widen to i16. -define i32 @test_widening_ok(i8* %P) nounwind ssp noredzone address_safety { +define i32 @test_widening_ok(i8* %P) nounwind ssp noredzone sanitize_address { entry: %tmp = load i8* getelementptr inbounds (%struct_of_7_bytes_4_aligned* @f, i64 0, i32 1), align 4 %conv = zext i8 %tmp to i32 diff --git a/test/Instrumentation/AddressSanitizer/basic.ll b/test/Instrumentation/AddressSanitizer/basic.ll index 655f69c16fdf3..fb32e704af86c 100644 --- a/test/Instrumentation/AddressSanitizer/basic.ll +++ b/test/Instrumentation/AddressSanitizer/basic.ll @@ -5,12 +5,12 @@ 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" -define i32 @test_load(i32* %a) address_safety { +define i32 @test_load(i32* %a) sanitize_address { ; CHECK: @test_load ; CHECK-NOT: load ; CHECK: %[[LOAD_ADDR:[^ ]*]] = ptrtoint i32* %a to i64 ; CHECK: lshr i64 %[[LOAD_ADDR]], 3 -; CHECK: or i64 +; CHECK: {{or|add}} ; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr ; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8* %[[LOAD_SHADOW_PTR]] ; CHECK: icmp ne i8 @@ -38,12 +38,12 @@ entry: ret i32 %tmp1 } -define void @test_store(i32* %a) address_safety { +define void @test_store(i32* %a) sanitize_address { ; CHECK: @test_store ; CHECK-NOT: store ; CHECK: %[[STORE_ADDR:[^ ]*]] = ptrtoint i32* %a to i64 ; CHECK: lshr i64 %[[STORE_ADDR]], 3 -; CHECK: or i64 +; CHECK: {{or|add}} ; CHECK: %[[STORE_SHADOW_PTR:[^ ]*]] = inttoptr ; CHECK: %[[STORE_SHADOW:[^ ]*]] = load i8* %[[STORE_SHADOW_PTR]] ; CHECK: icmp ne i8 @@ -73,7 +73,7 @@ entry: ; Check that asan leaves just one alloca. declare void @alloca_test_use([10 x i8]*) -define void @alloca_test() address_safety { +define void @alloca_test() sanitize_address { entry: %x = alloca [10 x i8], align 1 %y = alloca [10 x i8], align 1 @@ -89,3 +89,54 @@ entry: ; CHECK-NOT: = alloca ; CHECK: ret void +define void @LongDoubleTest(x86_fp80* nocapture %a) nounwind uwtable sanitize_address { +entry: + store x86_fp80 0xK3FFF8000000000000000, x86_fp80* %a, align 16 + ret void +} + +; CHECK: LongDoubleTest +; CHECK: __asan_report_store_n +; CHECK: __asan_report_store_n +; CHECK: ret void + + +define void @i40test(i40* %a, i40* %b) nounwind uwtable sanitize_address { + entry: + %t = load i40* %a + store i40 %t, i40* %b, align 8 + ret void +} + +; CHECK: i40test +; CHECK: __asan_report_load_n{{.*}}, i64 5) +; CHECK: __asan_report_load_n{{.*}}, i64 5) +; CHECK: __asan_report_store_n{{.*}}, i64 5) +; CHECK: __asan_report_store_n{{.*}}, i64 5) +; CHECK: ret void + +define void @i80test(i80* %a, i80* %b) nounwind uwtable sanitize_address { + entry: + %t = load i80* %a + store i80 %t, i80* %b, align 8 + ret void +} + +; CHECK: i80test +; CHECK: __asan_report_load_n{{.*}}, i64 10) +; CHECK: __asan_report_load_n{{.*}}, i64 10) +; CHECK: __asan_report_store_n{{.*}}, i64 10) +; CHECK: __asan_report_store_n{{.*}}, i64 10) +; CHECK: ret void + +; asan should not instrument functions with available_externally linkage. +define available_externally i32 @f_available_externally(i32* %a) sanitize_address { +entry: + %tmp1 = load i32* %a + ret i32 %tmp1 +} +; CHECK: @f_available_externally +; CHECK-NOT: __asan_report +; CHECK: ret i32 + + diff --git a/test/Instrumentation/AddressSanitizer/debug_info.ll b/test/Instrumentation/AddressSanitizer/debug_info.ll new file mode 100644 index 0000000000000..ec51caeb58687 --- /dev/null +++ b/test/Instrumentation/AddressSanitizer/debug_info.ll @@ -0,0 +1,61 @@ +; RUN: opt < %s -asan -asan-module -S | FileCheck %s + +; Checks that llvm.dbg.declare instructions are updated +; accordingly as we merge allocas. + +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-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @_Z3zzzi(i32 %p) nounwind uwtable sanitize_address { +entry: + %p.addr = alloca i32, align 4 + %r = alloca i32, align 4 + store i32 %p, i32* %p.addr, align 4 + call void @llvm.dbg.declare(metadata !{i32* %p.addr}, metadata !10), !dbg !11 + call void @llvm.dbg.declare(metadata !{i32* %r}, metadata !12), !dbg !14 + %0 = load i32* %p.addr, align 4, !dbg !14 + %add = add nsw i32 %0, 1, !dbg !14 + store i32 %add, i32* %r, align 4, !dbg !14 + %1 = load i32* %r, align 4, !dbg !15 + ret i32 %1, !dbg !15 +} + +; CHECK: define i32 @_Z3zzzi +; CHECK: entry: +; Verify that llvm.dbg.declare calls are in the entry basic block. +; CHECK-NOT: %entry +; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ARG_ID:[0-9]+]]) +; CHECK-NOT: %entry +; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[VAR_ID:[0-9]+]]) + +declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone + +!llvm.dbg.cu = !{!0} + +!0 = metadata !{i32 786449, i32 0, i32 4, metadata !"a.cc", metadata !"/usr/local/google/llvm_cmake_clang/tmp/debuginfo", metadata !"clang version 3.3 (trunk 169314)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !1} ; [ DW_TAG_compile_unit ] [/usr/local/google/llvm_cmake_clang/tmp/debuginfo/a.cc] [DW_LANG_C_plus_plus] +!1 = metadata !{metadata !2} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4} +!4 = metadata !{metadata !5} +!5 = metadata !{i32 786478, metadata !6, metadata !"zzz", metadata !"zzz", metadata !"_Z3zzzi", metadata !6, i32 1, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z3zzzi, null, null, metadata !1, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [zzz] +!6 = metadata !{i32 786473, metadata !16} ; [ DW_TAG_file_type ] +!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!8 = metadata !{metadata !9, metadata !9} +!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +!10 = metadata !{i32 786689, metadata !5, metadata !"p", metadata !6, i32 16777217, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [p] [line 1] +!11 = metadata !{i32 1, i32 0, metadata !5, null} +!12 = metadata !{i32 786688, metadata !13, metadata !"r", metadata !6, i32 2, metadata !9, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [r] [line 2] + +; Verify that debug descriptors for argument and local variable will be replaced +; with descriptors that end with OpDeref (encoded as 2). +; CHECK: ![[ARG_ID]] = metadata {{.*}} i64 2} ; [ DW_TAG_arg_variable ] [p] [line 1] +; CHECK: ![[VAR_ID]] = metadata {{.*}} i64 2} ; [ DW_TAG_auto_variable ] [r] [line 2] +; Verify that there are no more variable descriptors. +; CHECK-NOT: DW_TAG_arg_variable +; CHECK-NOT: DW_TAG_auto_variable + + +!13 = metadata !{i32 786443, metadata !5, i32 1, i32 0, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] [/usr/local/google/llvm_cmake_clang/tmp/debuginfo/a.cc] +!14 = metadata !{i32 2, i32 0, metadata !13, null} +!15 = metadata !{i32 3, i32 0, metadata !13, null} +!16 = metadata !{metadata !"a.cc", metadata !"/usr/local/google/llvm_cmake_clang/tmp/debuginfo"} diff --git a/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll b/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll new file mode 100644 index 0000000000000..b0371769be05a --- /dev/null +++ b/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll @@ -0,0 +1,41 @@ +; Test non-default shadow mapping scale and offset. +; +; RUN: opt < %s -asan -asan-mapping-scale=2 -asan-mapping-offset-log=0 -S | FileCheck %s + +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" + +; Test that ASan tells scale and offset to runtime. +; CHECK: @__asan_mapping_offset = linkonce_odr constant i64 0 +; CHECK: @__asan_mapping_scale = linkonce_odr constant i64 2 + +define i32 @test_load(i32* %a) sanitize_address { +; CHECK: @test_load +; CHECK-NOT: load +; CHECK: %[[LOAD_ADDR:[^ ]*]] = ptrtoint i32* %a to i64 +; CHECK: lshr i64 %[[LOAD_ADDR]], 2 + +; No need in shift for zero offset. +; CHECK-NOT: or i64 + +; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr +; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8* %[[LOAD_SHADOW_PTR]] +; CHECK: icmp ne i8 +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + +; No need in slow path for i32 and mapping scale equal to 2. +; CHECK-NOT: and i64 %[[LOAD_ADDR]] +; +; The crash block reports the error. +; CHECK: call void @__asan_report_load4(i64 %[[LOAD_ADDR]]) +; CHECK: unreachable +; +; The actual load. +; CHECK: %tmp1 = load i32* %a +; CHECK: ret i32 %tmp1 + +entry: + %tmp1 = load i32* %a + ret i32 %tmp1 +} + diff --git a/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll b/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll index 28d4ac0c0f589..0928c494154ef 100644 --- a/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll +++ b/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll @@ -5,7 +5,7 @@ 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-S128" target triple = "x86_64-unknown-linux-gnu" -define void @_Z3barv() uwtable address_safety { +define void @_Z3barv() uwtable sanitize_address { entry: %a = alloca i32, align 4 call void @_Z3fooPi(i32* %a) @@ -14,6 +14,7 @@ entry: declare void @_Z3fooPi(i32*) ; We create one global string constant for the stack frame above. +; It should have unnamed_addr and align 1. ; Make sure we don't create any other global constants. -; CHECK: = private constant -; CHECK-NOT: = private constant +; CHECK: = private unnamed_addr constant{{.*}}align 1 +; CHECK-NOT: = private unnamed_addr constant diff --git a/test/Instrumentation/AddressSanitizer/instrument-no-return.ll b/test/Instrumentation/AddressSanitizer/instrument-no-return.ll index 80f1b1c74cd11..2d835a34080a1 100644 --- a/test/Instrumentation/AddressSanitizer/instrument-no-return.ll +++ b/test/Instrumentation/AddressSanitizer/instrument-no-return.ll @@ -1,17 +1,49 @@ ; RUN: opt < %s -asan -S | FileCheck %s ; AddressSanitizer must insert __asan_handle_no_return -; before every noreturn call. +; 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 -define i32 @_Z5ChildPv(i8* nocapture %arg) uwtable address_safety { +define i32 @Call1(i8* nocapture %arg) uwtable sanitize_address { entry: - call void @MyNoReturnFunc(i32 1) noreturn + 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 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: call void @__asan_handle_no_return ; CHECK-NEXT: call void @MyNoReturnFunc +; CHECK-NEXT: unreachable + unreachable +} + +declare i32 @__gxx_personality_v0(...) + +define i64 @Invoke1(i8** %esc) nounwind uwtable ssp sanitize_address { +entry: + invoke void @MyNoReturnFunc(i32 1) + to label %invoke.cont unwind label %lpad + +invoke.cont: + ret i64 0 + +lpad: + %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + filter [0 x i8*] zeroinitializer + ret i64 1 +} +; CHECK: @Invoke1 +; CHECK: call void @__asan_handle_no_return +; CHECK-NEXT: invoke void @MyNoReturnFunc +; CHECK: ret i64 0 +; CHECK: ret i64 1 diff --git a/test/Instrumentation/AddressSanitizer/instrument_global.ll b/test/Instrumentation/AddressSanitizer/instrument_global.ll index 3d92946087ecf..2c183f523feb2 100644 --- a/test/Instrumentation/AddressSanitizer/instrument_global.ll +++ b/test/Instrumentation/AddressSanitizer/instrument_global.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -asan -S | FileCheck %s +; RUN: opt < %s -asan -asan-module -S | FileCheck %s 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" @xxx = global i32 0, align 4 diff --git a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll index 472551654e539..1d00cfacafe4a 100644 --- a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll +++ b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll @@ -1,11 +1,15 @@ -; RUN: opt < %s -asan -asan-initialization-order -S | FileCheck %s +; RUN: opt < %s -asan -asan-module -S | FileCheck %s 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" -@xxx = global i32 0, align 4 +@xxx = internal global i32 0, align 4 ; With dynamic initializer. +@XXX = global i32 0, align 4 ; With dynamic initializer. +@yyy = internal global i32 0, align 4 ; W/o dynamic initializer. +@YYY = global i32 0, align 4 ; W/o dynamic initializer. ; Clang will emit the following metadata identifying @xxx as dynamically ; initialized. !0 = metadata !{i32* @xxx} -!llvm.asan.dynamically_initialized_globals = !{!0} +!1 = metadata !{i32* @XXX} +!llvm.asan.dynamically_initialized_globals = !{!0, !1} define i32 @initializer() uwtable { entry: @@ -19,7 +23,7 @@ entry: ret void } -define internal void @_GLOBAL__I_a() address_safety section ".text.startup" { +define internal void @_GLOBAL__I_a() sanitize_address section ".text.startup" { entry: call void @__cxx_global_var_init() ret void @@ -34,3 +38,40 @@ entry: ; CHECK: call void @__cxx_global_var_init ; CHECK: call void @__asan_after_dynamic_init ; CHECK: ret + +; Check that xxx is instrumented. +define void @touch_xxx() sanitize_address { + store i32 0, i32 *@xxx, align 4 + ret void +; CHECK: define void @touch_xxx +; CHECK: call void @__asan_report_store4 +; CHECK: ret void +} + +; Check that XXX is instrumented. +define void @touch_XXX() sanitize_address { + store i32 0, i32 *@XXX, align 4 + ret void +; CHECK: define void @touch_XXX +; CHECK: call void @__asan_report_store4 +; CHECK: ret void +} + + +; Check that yyy is NOT instrumented (as it does not have dynamic initializer). +define void @touch_yyy() sanitize_address { + store i32 0, i32 *@yyy, align 4 + ret void +; CHECK: define void @touch_yyy +; CHECK-NOT: call void @__asan_report_store4 +; CHECK: ret void +} + +; Check that YYY is NOT instrumented (as it does not have dynamic initializer). +define void @touch_YYY() sanitize_address { + store i32 0, i32 *@YYY, align 4 + ret void +; CHECK: define void @touch_YYY +; CHECK-NOT: call void @__asan_report_store4 +; CHECK: ret void +} diff --git a/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll b/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll index 633bf9ae78c02..23cf6d28ec6cd 100644 --- a/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll +++ b/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll @@ -4,7 +4,7 @@ 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" -define void @IncrementMe(i32* %a) address_safety { +define void @IncrementMe(i32* %a) sanitize_address { entry: %tmp1 = load i32* %a, align 4 %tmp2 = add i32 %tmp1, 1 diff --git a/test/Instrumentation/AddressSanitizer/lifetime.ll b/test/Instrumentation/AddressSanitizer/lifetime.ll new file mode 100644 index 0000000000000..334872865f1a0 --- /dev/null +++ b/test/Instrumentation/AddressSanitizer/lifetime.ll @@ -0,0 +1,84 @@ +; Test hanlding of llvm.lifetime intrinsics. +; RUN: opt < %s -asan -asan-check-lifetime -S | FileCheck %s + +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-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind + +define void @lifetime_no_size() sanitize_address { +entry: + %i = alloca i32, align 4 + %i.ptr = bitcast i32* %i to i8* + call void @llvm.lifetime.start(i64 -1, i8* %i.ptr) + call void @llvm.lifetime.end(i64 -1, i8* %i.ptr) + +; Check that lifetime with no size are ignored. +; CHECK: @lifetime_no_size +; CHECK-NOT: @__asan_poison_stack_memory +; CHECK-NOT: @__asan_unpoison_stack_memory +; CHECK: ret void + ret void +} + +; Generic case of lifetime analysis. +define void @lifetime() sanitize_address { + ; CHECK: @lifetime + + ; Regular variable lifetime intrinsics. + %i = alloca i32, align 4 + %i.ptr = bitcast i32* %i to i8* + call void @llvm.lifetime.start(i64 3, i8* %i.ptr) + ; Memory is unpoisoned at llvm.lifetime.start + ; CHECK: %[[VAR:[^ ]*]] = ptrtoint i32* %{{[^ ]+}} to i64 + ; CHECK-NEXT: call void @__asan_unpoison_stack_memory(i64 %[[VAR]], i64 3) + call void @llvm.lifetime.end(i64 4, i8* %i.ptr) + call void @llvm.lifetime.end(i64 2, i8* %i.ptr) + ; Memory is poisoned at every call to llvm.lifetime.end + ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4) + ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 2) + + ; Lifetime intrinsics for array. + %arr = alloca [10 x i32], align 16 + %arr.ptr = bitcast [10 x i32]* %arr to i8* + call void @llvm.lifetime.start(i64 40, i8* %arr.ptr) + ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 40) + call void @llvm.lifetime.end(i64 40, i8* %arr.ptr) + ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 40) + + ; One more lifetime start/end for the same variable %i. + call void @llvm.lifetime.start(i64 4, i8* %i.ptr) + ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 4) + call void @llvm.lifetime.end(i64 4, i8* %i.ptr) + ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4) + + ; Memory is unpoisoned at function exit (only once). + ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 {{.*}}) + ; CHECK-NOT: @__asan_unpoison_stack_memory + ; CHECK: ret void + ret void +} + +; Check that arguments of lifetime may come from phi nodes. +define void @phi_args(i1 %x) sanitize_address { + ; CHECK: @phi_args + +entry: + %i = alloca i64, align 4 + %i.ptr = bitcast i64* %i to i8* + call void @llvm.lifetime.start(i64 8, i8* %i.ptr) + ; CHECK: __asan_unpoison_stack_memory + br i1 %x, label %bb0, label %bb1 + +bb0: + %i.ptr2 = bitcast i64* %i to i8* + br label %bb1 + +bb1: + %i.phi = phi i8* [ %i.ptr, %entry ], [ %i.ptr2, %bb0 ] + call void @llvm.lifetime.end(i64 8, i8* %i.phi) + ; CHECK: __asan_poison_stack_memory + ; CHECK: ret void + ret void +} diff --git a/test/Instrumentation/AddressSanitizer/test64.ll b/test/Instrumentation/AddressSanitizer/test64.ll index d544d77b93db9..6aa5c28850994 100644 --- a/test/Instrumentation/AddressSanitizer/test64.ll +++ b/test/Instrumentation/AddressSanitizer/test64.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -asan -S | FileCheck %s 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" -define i32 @read_4_bytes(i32* %a) address_safety { +define i32 @read_4_bytes(i32* %a) sanitize_address { entry: %tmp1 = load i32* %a, align 4 ret i32 %tmp1 @@ -9,11 +9,11 @@ entry: ; CHECK: @read_4_bytes ; CHECK-NOT: ret ; CHECK: lshr {{.*}} 3 -; Check for ASAN's Offset for 64-bit (2^44) -; CHECK-NEXT: 17592186044416 +; Check for ASAN's Offset for 64-bit (2^44 or 7fff8000) +; CHECK-NEXT: {{17592186044416|2147450880}} ; CHECK: ret -define void @example_atomicrmw(i64* %ptr) nounwind uwtable address_safety { +define void @example_atomicrmw(i64* %ptr) nounwind uwtable sanitize_address { entry: %0 = atomicrmw add i64* %ptr, i64 1 seq_cst ret void @@ -24,7 +24,7 @@ entry: ; CHECK: atomicrmw ; CHECK: ret -define void @example_cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) nounwind uwtable address_safety { +define void @example_cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) nounwind uwtable sanitize_address { entry: %0 = cmpxchg i64* %ptr, i64 %compare_to, i64 %new_value seq_cst ret void diff --git a/test/Instrumentation/MemorySanitizer/lit.local.cfg b/test/Instrumentation/MemorySanitizer/lit.local.cfg new file mode 100644 index 0000000000000..19eebc0ac7ac3 --- /dev/null +++ b/test/Instrumentation/MemorySanitizer/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Instrumentation/MemorySanitizer/msan_basic.ll b/test/Instrumentation/MemorySanitizer/msan_basic.ll new file mode 100644 index 0000000000000..1e7a31793deae --- /dev/null +++ b/test/Instrumentation/MemorySanitizer/msan_basic.ll @@ -0,0 +1,625 @@ +; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck %s +; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck -check-prefix=CHECK-ORIGINS %s +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-S128" + +; Check the presence of __msan_init +; CHECK: @llvm.global_ctors {{.*}} @__msan_init + +; Check the presence and the linkage type of __msan_track_origins +; CHECK: @__msan_track_origins = weak_odr constant i32 0 + + +; Check instrumentation of stores + +define void @Store(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory { +entry: + store i32 %x, i32* %p, align 4 + ret void +} + +; CHECK: @Store +; CHECK: load {{.*}} @__msan_param_tls +; CHECK: store +; CHECK: store +; CHECK: ret void +; CHECK-ORIGINS: @Store +; CHECK-ORIGINS: load {{.*}} @__msan_param_tls +; CHECK-ORIGINS: store +; CHECK-ORIGINS: icmp +; CHECK-ORIGINS: br i1 +; CHECK-ORIGINS: <label> +; CHECK-ORIGINS: store +; CHECK-ORIGINS: br label +; CHECK-ORIGINS: <label> +; CHECK-ORIGINS: store +; CHECK-ORIGINS: ret void + + +; Check instrumentation of aligned stores +; Shadow store has the same alignment as the original store; origin store +; does not specify explicit alignment. + +define void @AlignedStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory { +entry: + store i32 %x, i32* %p, align 32 + ret void +} + +; CHECK: @AlignedStore +; CHECK: load {{.*}} @__msan_param_tls +; CHECK: store {{.*}} align 32 +; CHECK: store {{.*}} align 32 +; CHECK: ret void +; CHECK-ORIGINS: @AlignedStore +; CHECK-ORIGINS: load {{.*}} @__msan_param_tls +; CHECK-ORIGINS: store {{.*}} align 32 +; CHECK-ORIGINS: icmp +; CHECK-ORIGINS: br i1 +; CHECK-ORIGINS: <label> +; CHECK-ORIGINS: store {{.*}} align 32 +; CHECK-ORIGINS: br label +; CHECK-ORIGINS: <label> +; CHECK-ORIGINS: store {{.*}} align 32 +; CHECK-ORIGINS: ret void + + +; load followed by cmp: check that we load the shadow and call __msan_warning. +define void @LoadAndCmp(i32* nocapture %a) nounwind uwtable sanitize_memory { +entry: + %0 = load i32* %a, align 4 + %tobool = icmp eq i32 %0, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + tail call void (...)* @foo() nounwind + br label %if.end + +if.end: ; preds = %entry, %if.then + ret void +} + +declare void @foo(...) + +; CHECK: @LoadAndCmp +; CHECK: = load +; CHECK: = load +; CHECK: call void @__msan_warning_noreturn() +; CHECK-NEXT: call void asm sideeffect +; CHECK-NEXT: unreachable +; CHECK: ret void + +; Check that we store the shadow for the retval. +define i32 @ReturnInt() nounwind uwtable readnone sanitize_memory { +entry: + ret i32 123 +} + +; CHECK: @ReturnInt +; CHECK: store i32 0,{{.*}}__msan_retval_tls +; CHECK: ret i32 + +; Check that we get the shadow for the retval. +define void @CopyRetVal(i32* nocapture %a) nounwind uwtable sanitize_memory { +entry: + %call = tail call i32 @ReturnInt() nounwind + store i32 %call, i32* %a, align 4 + ret void +} + +; CHECK: @CopyRetVal +; CHECK: load{{.*}}__msan_retval_tls +; CHECK: store +; CHECK: store +; CHECK: ret void + + +; Check that we generate PHIs for shadow. +define void @FuncWithPhi(i32* nocapture %a, i32* %b, i32* nocapture %c) nounwind uwtable sanitize_memory { +entry: + %tobool = icmp eq i32* %b, null + br i1 %tobool, label %if.else, label %if.then + + if.then: ; preds = %entry + %0 = load i32* %b, align 4 + br label %if.end + + if.else: ; preds = %entry + %1 = load i32* %c, align 4 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %t.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ] + store i32 %t.0, i32* %a, align 4 + ret void +} + +; CHECK: @FuncWithPhi +; CHECK: = phi +; CHECK-NEXT: = phi +; CHECK: store +; CHECK: store +; CHECK: ret void + +; Compute shadow for "x << 10" +define void @ShlConst(i32* nocapture %x) nounwind uwtable sanitize_memory { +entry: + %0 = load i32* %x, align 4 + %1 = shl i32 %0, 10 + store i32 %1, i32* %x, align 4 + ret void +} + +; CHECK: @ShlConst +; CHECK: = load +; CHECK: = load +; CHECK: shl +; CHECK: shl +; CHECK: store +; CHECK: store +; CHECK: ret void + +; Compute shadow for "10 << x": it should have 'sext i1'. +define void @ShlNonConst(i32* nocapture %x) nounwind uwtable sanitize_memory { +entry: + %0 = load i32* %x, align 4 + %1 = shl i32 10, %0 + store i32 %1, i32* %x, align 4 + ret void +} + +; CHECK: @ShlNonConst +; CHECK: = load +; CHECK: = load +; CHECK: = sext i1 +; CHECK: store +; CHECK: store +; CHECK: ret void + +; SExt +define void @SExt(i32* nocapture %a, i16* nocapture %b) nounwind uwtable sanitize_memory { +entry: + %0 = load i16* %b, align 2 + %1 = sext i16 %0 to i32 + store i32 %1, i32* %a, align 4 + ret void +} + +; CHECK: @SExt +; CHECK: = load +; CHECK: = load +; CHECK: = sext +; CHECK: = sext +; CHECK: store +; CHECK: store +; CHECK: ret void + + +; memset +define void @MemSet(i8* nocapture %x) nounwind uwtable sanitize_memory { +entry: + call void @llvm.memset.p0i8.i64(i8* %x, i8 42, i64 10, i32 1, i1 false) + ret void +} + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind + +; CHECK: @MemSet +; CHECK: call i8* @__msan_memset +; CHECK: ret void + + +; memcpy +define void @MemCpy(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory { +entry: + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + +; CHECK: @MemCpy +; CHECK: call i8* @__msan_memcpy +; CHECK: ret void + + +; memmove is lowered to a call +define void @MemMove(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory { +entry: + call void @llvm.memmove.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false) + ret void +} + +declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + +; CHECK: @MemMove +; CHECK: call i8* @__msan_memmove +; CHECK: ret void + + +; Check that we propagate shadow for "select" + +define i32 @Select(i32 %a, i32 %b, i32 %c) nounwind uwtable readnone sanitize_memory { +entry: + %tobool = icmp ne i32 %c, 0 + %cond = select i1 %tobool, i32 %a, i32 %b + ret i32 %cond +} + +; CHECK: @Select +; CHECK: select +; CHECK-NEXT: select +; CHECK: ret i32 + + +; Check that we propagate origin for "select" with vector condition. +; Select condition is flattened to i1, which is then used to select one of the +; argument origins. + +define <8 x i16> @SelectVector(<8 x i16> %a, <8 x i16> %b, <8 x i1> %c) nounwind uwtable readnone sanitize_memory { +entry: + %cond = select <8 x i1> %c, <8 x i16> %a, <8 x i16> %b + ret <8 x i16> %cond +} + +; CHECK-ORIGINS: @SelectVector +; CHECK-ORIGINS: bitcast <8 x i1> {{.*}} to i8 +; CHECK-ORIGINS: icmp ne i8 +; CHECK-ORIGINS: select i1 +; CHECK-ORIGINS: ret <8 x i16> + + +define i8* @IntToPtr(i64 %x) nounwind uwtable readnone sanitize_memory { +entry: + %0 = inttoptr i64 %x to i8* + ret i8* %0 +} + +; CHECK: @IntToPtr +; CHECK: load i64*{{.*}}__msan_param_tls +; CHECK-NEXT: inttoptr +; CHECK-NEXT: store i64{{.*}}__msan_retval_tls +; CHECK: ret i8 + + +define i8* @IntToPtr_ZExt(i16 %x) nounwind uwtable readnone sanitize_memory { +entry: + %0 = inttoptr i16 %x to i8* + ret i8* %0 +} + +; CHECK: @IntToPtr_ZExt +; CHECK: zext +; CHECK-NEXT: inttoptr +; CHECK: ret i8 + + +; Check that we insert exactly one check on udiv +; (2nd arg shadow is checked, 1st arg shadow is propagated) + +define i32 @Div(i32 %a, i32 %b) nounwind uwtable readnone sanitize_memory { +entry: + %div = udiv i32 %a, %b + ret i32 %div +} + +; CHECK: @Div +; CHECK: icmp +; CHECK: call void @__msan_warning +; CHECK-NOT: icmp +; CHECK: udiv +; CHECK-NOT: icmp +; CHECK: ret i32 + + +; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests) + +define zeroext i1 @ICmpSLT(i32 %x) nounwind uwtable readnone sanitize_memory { + %1 = icmp slt i32 %x, 0 + ret i1 %1 +} + +; CHECK: @ICmpSLT +; CHECK: icmp slt +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp slt +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i1 + +define zeroext i1 @ICmpSGE(i32 %x) nounwind uwtable readnone sanitize_memory { + %1 = icmp sge i32 %x, 0 + ret i1 %1 +} + +; CHECK: @ICmpSGE +; CHECK: icmp slt +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp sge +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i1 + +define zeroext i1 @ICmpSGT(i32 %x) nounwind uwtable readnone sanitize_memory { + %1 = icmp sgt i32 0, %x + ret i1 %1 +} + +; CHECK: @ICmpSGT +; CHECK: icmp slt +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp sgt +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i1 + +define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone sanitize_memory { + %1 = icmp sle i32 0, %x + ret i1 %1 +} + +; CHECK: @ICmpSLE +; CHECK: icmp slt +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp sle +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i1 + + +; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests) +; of the vector arguments. + +define <2 x i1> @ICmpSLT_vector(<2 x i32*> %x) nounwind uwtable readnone sanitize_memory { + %1 = icmp slt <2 x i32*> %x, zeroinitializer + ret <2 x i1> %1 +} + +; CHECK: @ICmpSLT_vector +; CHECK: icmp slt <2 x i64> +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp slt <2 x i32*> +; CHECK-NOT: call void @__msan_warning +; CHECK: ret <2 x i1> + + +; Check that we propagate shadow for unsigned relational comparisons with +; constants + +define zeroext i1 @ICmpUGTConst(i32 %x) nounwind uwtable readnone sanitize_memory { +entry: + %cmp = icmp ugt i32 %x, 7 + ret i1 %cmp +} + +; CHECK: @ICmpUGTConst +; CHECK: icmp ugt i32 +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp ugt i32 +; CHECK-NOT: call void @__msan_warning +; CHECK: icmp ugt i32 +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i1 + + +; Check that loads of shadow have the same aligment as the original loads. +; Check that loads of origin have the aligment of max(4, original alignment). + +define i32 @ShadowLoadAlignmentLarge() nounwind uwtable sanitize_memory { + %y = alloca i32, align 64 + %1 = load volatile i32* %y, align 64 + ret i32 %1 +} + +; CHECK: @ShadowLoadAlignmentLarge +; CHECK: load i32* {{.*}} align 64 +; CHECK: load volatile i32* {{.*}} align 64 +; CHECK: ret i32 + +define i32 @ShadowLoadAlignmentSmall() nounwind uwtable sanitize_memory { + %y = alloca i32, align 2 + %1 = load volatile i32* %y, align 2 + ret i32 %1 +} + +; CHECK: @ShadowLoadAlignmentSmall +; CHECK: load i32* {{.*}} align 2 +; CHECK: load volatile i32* {{.*}} align 2 +; CHECK: ret i32 + +; CHECK-ORIGINS: @ShadowLoadAlignmentSmall +; CHECK-ORIGINS: load i32* {{.*}} align 2 +; CHECK-ORIGINS: load i32* {{.*}} align 4 +; CHECK-ORIGINS: load volatile i32* {{.*}} align 2 +; CHECK-ORIGINS: ret i32 + + +; Test vector manipulation instructions. +; Check that the same bit manipulation is applied to the shadow values. +; Check that there is a zero test of the shadow of %idx argument, where present. + +define i32 @ExtractElement(<4 x i32> %vec, i32 %idx) sanitize_memory { + %x = extractelement <4 x i32> %vec, i32 %idx + ret i32 %x +} + +; CHECK: @ExtractElement +; CHECK: extractelement +; CHECK: call void @__msan_warning +; CHECK: extractelement +; CHECK: ret i32 + +define <4 x i32> @InsertElement(<4 x i32> %vec, i32 %idx, i32 %x) sanitize_memory { + %vec1 = insertelement <4 x i32> %vec, i32 %x, i32 %idx + ret <4 x i32> %vec1 +} + +; CHECK: @InsertElement +; CHECK: insertelement +; CHECK: call void @__msan_warning +; CHECK: insertelement +; CHECK: ret <4 x i32> + +define <4 x i32> @ShuffleVector(<4 x i32> %vec, <4 x i32> %vec1) sanitize_memory { + %vec2 = shufflevector <4 x i32> %vec, <4 x i32> %vec1, + <4 x i32> <i32 0, i32 4, i32 1, i32 5> + ret <4 x i32> %vec2 +} + +; CHECK: @ShuffleVector +; CHECK: shufflevector +; CHECK-NOT: call void @__msan_warning +; CHECK: shufflevector +; CHECK: ret <4 x i32> + + +; Test bswap intrinsic instrumentation +define i32 @BSwap(i32 %x) nounwind uwtable readnone sanitize_memory { + %y = tail call i32 @llvm.bswap.i32(i32 %x) + ret i32 %y +} + +declare i32 @llvm.bswap.i32(i32) nounwind readnone + +; CHECK: @BSwap +; CHECK-NOT: call void @__msan_warning +; CHECK: @llvm.bswap.i32 +; CHECK-NOT: call void @__msan_warning +; CHECK: @llvm.bswap.i32 +; CHECK-NOT: call void @__msan_warning +; CHECK: ret i32 + + +; Store intrinsic. + +define void @StoreIntrinsic(i8* %p, <4 x float> %x) nounwind uwtable sanitize_memory { + call void @llvm.x86.sse.storeu.ps(i8* %p, <4 x float> %x) + ret void +} + +declare void @llvm.x86.sse.storeu.ps(i8*, <4 x float>) nounwind + +; CHECK: @StoreIntrinsic +; CHECK-NOT: br +; CHECK-NOT: = or +; CHECK: store <4 x i32> {{.*}} align 1 +; CHECK: call void @llvm.x86.sse.storeu.ps +; CHECK: ret void + + +; Load intrinsic. + +define <16 x i8> @LoadIntrinsic(i8* %p) nounwind uwtable sanitize_memory { + %call = call <16 x i8> @llvm.x86.sse3.ldu.dq(i8* %p) + ret <16 x i8> %call +} + +declare <16 x i8> @llvm.x86.sse3.ldu.dq(i8* %p) nounwind + +; CHECK: @LoadIntrinsic +; CHECK: load <16 x i8>* {{.*}} align 1 +; CHECK-NOT: br +; CHECK-NOT: = or +; CHECK: call <16 x i8> @llvm.x86.sse3.ldu.dq +; CHECK: store <16 x i8> {{.*}} @__msan_retval_tls +; CHECK: ret <16 x i8> + +; CHECK-ORIGINS: @LoadIntrinsic +; CHECK-ORIGINS: [[ORIGIN:%[01-9a-z]+]] = load i32* {{.*}} +; CHECK-ORIGINS: call <16 x i8> @llvm.x86.sse3.ldu.dq +; CHECK-ORIGINS: store i32 {{.*}}[[ORIGIN]], i32* @__msan_retval_origin_tls +; CHECK-ORIGINS: ret <16 x i8> + + +; Simple NoMem intrinsic +; Check that shadow is OR'ed, and origin is Select'ed +; And no shadow checks! + +define <8 x i16> @Paddsw128(<8 x i16> %a, <8 x i16> %b) nounwind uwtable sanitize_memory { + %call = call <8 x i16> @llvm.x86.sse2.padds.w(<8 x i16> %a, <8 x i16> %b) + ret <8 x i16> %call +} + +declare <8 x i16> @llvm.x86.sse2.padds.w(<8 x i16> %a, <8 x i16> %b) nounwind + +; CHECK: @Paddsw128 +; CHECK-NEXT: load <8 x i16>* {{.*}} @__msan_param_tls +; CHECK-NEXT: load <8 x i16>* {{.*}} @__msan_param_tls +; CHECK-NEXT: = or <8 x i16> +; CHECK-NEXT: call <8 x i16> @llvm.x86.sse2.padds.w +; CHECK-NEXT: store <8 x i16> {{.*}} @__msan_retval_tls +; CHECK-NEXT: ret <8 x i16> + +; CHECK-ORIGINS: @Paddsw128 +; CHECK-ORIGINS: load i32* {{.*}} @__msan_param_origin_tls +; CHECK-ORIGINS: load i32* {{.*}} @__msan_param_origin_tls +; CHECK-ORIGINS: = bitcast <8 x i16> {{.*}} to i128 +; CHECK-ORIGINS-NEXT: = icmp ne i128 {{.*}}, 0 +; CHECK-ORIGINS-NEXT: = select i1 {{.*}}, i32 {{.*}}, i32 +; CHECK-ORIGINS: call <8 x i16> @llvm.x86.sse2.padds.w +; CHECK-ORIGINS: store i32 {{.*}} @__msan_retval_origin_tls +; CHECK-ORIGINS: ret <8 x i16> + + +; Test handling of vectors of pointers. +; Check that shadow of such vector is a vector of integers. + +define <8 x i8*> @VectorOfPointers(<8 x i8*>* %p) nounwind uwtable sanitize_memory { + %x = load <8 x i8*>* %p + ret <8 x i8*> %x +} + +; CHECK: @VectorOfPointers +; CHECK: load <8 x i64>* +; CHECK: load <8 x i8*>* +; CHECK: store <8 x i64> {{.*}} @__msan_retval_tls +; CHECK: ret <8 x i8*> + +; Test handling of va_copy. + +declare void @llvm.va_copy(i8*, i8*) nounwind + +define void @VACopy(i8* %p1, i8* %p2) nounwind uwtable sanitize_memory { + call void @llvm.va_copy(i8* %p1, i8* %p2) nounwind + ret void +} + +; CHECK: @VACopy +; CHECK: call void @llvm.memset.p0i8.i64({{.*}}, i8 0, i64 24, i32 8, i1 false) +; CHECK: ret void + + +; Test handling of volatile stores. +; Check that MemorySanitizer does not add a check of the value being stored. + +define void @VolatileStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory { +entry: + store volatile i32 %x, i32* %p, align 4 + ret void +} + +; CHECK: @VolatileStore +; CHECK-NOT: @__msan_warning +; CHECK: ret void + + +; Test that checks are omitted but shadow propagation is kept if +; sanitize_memory attribute is missing. + +define i32 @NoSanitizeMemory(i32 %x) uwtable { +entry: + %tobool = icmp eq i32 %x, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + tail call void @bar() + br label %if.end + +if.end: ; preds = %entry, %if.then + ret i32 %x +} + +declare void @bar() + +; CHECK: @NoSanitizeMemory +; CHECK-NOT: @__msan_warning +; CHECK: load i32* {{.*}} @__msan_param_tls +; CHECK-NOT: @__msan_warning +; CHECK: store {{.*}} @__msan_retval_tls +; CHECK-NOT: @__msan_warning +; CHECK: ret i32 diff --git a/test/Instrumentation/MemorySanitizer/unreachable.ll b/test/Instrumentation/MemorySanitizer/unreachable.ll new file mode 100644 index 0000000000000..c8130717c7daa --- /dev/null +++ b/test/Instrumentation/MemorySanitizer/unreachable.ll @@ -0,0 +1,39 @@ +; RUN: opt < %s -msan -S | FileCheck %s +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-S128" +target triple = "x86_64-unknown-linux-gnu" + + +; Test that MemorySanitizer correctly handles unreachable blocks. + +define i32 @Func(i32* %p) nounwind uwtable { +entry: + br label %exit + +unreachable: + %x = load i32* %p + br label %exit + +exit: + %z = phi i32 [ 42, %entry ], [ %x, %unreachable ] + ret i32 %z +} + +; CHECK: @Func +; CHECK: store i32 0, {{.*}} @__msan_retval_tls +; CHECK: ret i32 42 + + +define i32 @UnreachableLoop() nounwind uwtable { +entry: + ret i32 0 + +zzz: + br label %xxx + +xxx: + br label %zzz +} + +; CHECK: @UnreachableLoop +; CHECK: store i32 0, {{.*}} @__msan_retval_tls +; CHECK: ret i32 0 diff --git a/test/Instrumentation/ThreadSanitizer/atomic.ll b/test/Instrumentation/ThreadSanitizer/atomic.ll index 107dbdc0f227b..70b6cbbf31050 100644 --- a/test/Instrumentation/ThreadSanitizer/atomic.ll +++ b/test/Instrumentation/ThreadSanitizer/atomic.ll @@ -114,6 +114,14 @@ entry: ; CHECK: atomic8_xor_monotonic ; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 0) +define void @atomic8_nand_monotonic(i8* %a) nounwind uwtable { +entry: + atomicrmw nand i8* %a, i8 0 monotonic + ret void +} +; CHECK: atomic8_nand_monotonic +; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 0) + define void @atomic8_xchg_acquire(i8* %a) nounwind uwtable { entry: atomicrmw xchg i8* %a, i8 0 acquire @@ -162,6 +170,14 @@ entry: ; CHECK: atomic8_xor_acquire ; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 2) +define void @atomic8_nand_acquire(i8* %a) nounwind uwtable { +entry: + atomicrmw nand i8* %a, i8 0 acquire + ret void +} +; CHECK: atomic8_nand_acquire +; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 2) + define void @atomic8_xchg_release(i8* %a) nounwind uwtable { entry: atomicrmw xchg i8* %a, i8 0 release @@ -210,6 +226,14 @@ entry: ; CHECK: atomic8_xor_release ; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 3) +define void @atomic8_nand_release(i8* %a) nounwind uwtable { +entry: + atomicrmw nand i8* %a, i8 0 release + ret void +} +; CHECK: atomic8_nand_release +; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 3) + define void @atomic8_xchg_acq_rel(i8* %a) nounwind uwtable { entry: atomicrmw xchg i8* %a, i8 0 acq_rel @@ -258,6 +282,14 @@ entry: ; CHECK: atomic8_xor_acq_rel ; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 4) +define void @atomic8_nand_acq_rel(i8* %a) nounwind uwtable { +entry: + atomicrmw nand i8* %a, i8 0 acq_rel + ret void +} +; CHECK: atomic8_nand_acq_rel +; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 4) + define void @atomic8_xchg_seq_cst(i8* %a) nounwind uwtable { entry: atomicrmw xchg i8* %a, i8 0 seq_cst @@ -306,13 +338,21 @@ entry: ; CHECK: atomic8_xor_seq_cst ; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 5) +define void @atomic8_nand_seq_cst(i8* %a) nounwind uwtable { +entry: + atomicrmw nand i8* %a, i8 0 seq_cst + ret void +} +; CHECK: atomic8_nand_seq_cst +; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 5) + define void @atomic8_cas_monotonic(i8* %a) nounwind uwtable { entry: cmpxchg i8* %a, i8 0, i8 1 monotonic ret void } ; CHECK: atomic8_cas_monotonic -; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0) +; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0, i32 0) define void @atomic8_cas_acquire(i8* %a) nounwind uwtable { entry: @@ -320,7 +360,7 @@ entry: ret void } ; CHECK: atomic8_cas_acquire -; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2) +; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2, i32 2) define void @atomic8_cas_release(i8* %a) nounwind uwtable { entry: @@ -328,7 +368,7 @@ entry: ret void } ; CHECK: atomic8_cas_release -; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3) +; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3, i32 0) define void @atomic8_cas_acq_rel(i8* %a) nounwind uwtable { entry: @@ -336,7 +376,7 @@ entry: ret void } ; CHECK: atomic8_cas_acq_rel -; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4) +; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4, i32 2) define void @atomic8_cas_seq_cst(i8* %a) nounwind uwtable { entry: @@ -344,7 +384,7 @@ entry: ret void } ; CHECK: atomic8_cas_seq_cst -; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5) +; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5, i32 5) define i16 @atomic16_load_unordered(i16* %a) nounwind uwtable { entry: @@ -458,6 +498,14 @@ entry: ; CHECK: atomic16_xor_monotonic ; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 0) +define void @atomic16_nand_monotonic(i16* %a) nounwind uwtable { +entry: + atomicrmw nand i16* %a, i16 0 monotonic + ret void +} +; CHECK: atomic16_nand_monotonic +; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 0) + define void @atomic16_xchg_acquire(i16* %a) nounwind uwtable { entry: atomicrmw xchg i16* %a, i16 0 acquire @@ -506,6 +554,14 @@ entry: ; CHECK: atomic16_xor_acquire ; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 2) +define void @atomic16_nand_acquire(i16* %a) nounwind uwtable { +entry: + atomicrmw nand i16* %a, i16 0 acquire + ret void +} +; CHECK: atomic16_nand_acquire +; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 2) + define void @atomic16_xchg_release(i16* %a) nounwind uwtable { entry: atomicrmw xchg i16* %a, i16 0 release @@ -554,6 +610,14 @@ entry: ; CHECK: atomic16_xor_release ; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 3) +define void @atomic16_nand_release(i16* %a) nounwind uwtable { +entry: + atomicrmw nand i16* %a, i16 0 release + ret void +} +; CHECK: atomic16_nand_release +; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 3) + define void @atomic16_xchg_acq_rel(i16* %a) nounwind uwtable { entry: atomicrmw xchg i16* %a, i16 0 acq_rel @@ -602,6 +666,14 @@ entry: ; CHECK: atomic16_xor_acq_rel ; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 4) +define void @atomic16_nand_acq_rel(i16* %a) nounwind uwtable { +entry: + atomicrmw nand i16* %a, i16 0 acq_rel + ret void +} +; CHECK: atomic16_nand_acq_rel +; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 4) + define void @atomic16_xchg_seq_cst(i16* %a) nounwind uwtable { entry: atomicrmw xchg i16* %a, i16 0 seq_cst @@ -650,13 +722,21 @@ entry: ; CHECK: atomic16_xor_seq_cst ; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 5) +define void @atomic16_nand_seq_cst(i16* %a) nounwind uwtable { +entry: + atomicrmw nand i16* %a, i16 0 seq_cst + ret void +} +; CHECK: atomic16_nand_seq_cst +; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 5) + define void @atomic16_cas_monotonic(i16* %a) nounwind uwtable { entry: cmpxchg i16* %a, i16 0, i16 1 monotonic ret void } ; CHECK: atomic16_cas_monotonic -; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0) +; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0, i32 0) define void @atomic16_cas_acquire(i16* %a) nounwind uwtable { entry: @@ -664,7 +744,7 @@ entry: ret void } ; CHECK: atomic16_cas_acquire -; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2) +; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2, i32 2) define void @atomic16_cas_release(i16* %a) nounwind uwtable { entry: @@ -672,7 +752,7 @@ entry: ret void } ; CHECK: atomic16_cas_release -; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3) +; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3, i32 0) define void @atomic16_cas_acq_rel(i16* %a) nounwind uwtable { entry: @@ -680,7 +760,7 @@ entry: ret void } ; CHECK: atomic16_cas_acq_rel -; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4) +; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4, i32 2) define void @atomic16_cas_seq_cst(i16* %a) nounwind uwtable { entry: @@ -688,7 +768,7 @@ entry: ret void } ; CHECK: atomic16_cas_seq_cst -; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5) +; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5, i32 5) define i32 @atomic32_load_unordered(i32* %a) nounwind uwtable { entry: @@ -802,6 +882,14 @@ entry: ; CHECK: atomic32_xor_monotonic ; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 0) +define void @atomic32_nand_monotonic(i32* %a) nounwind uwtable { +entry: + atomicrmw nand i32* %a, i32 0 monotonic + ret void +} +; CHECK: atomic32_nand_monotonic +; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 0) + define void @atomic32_xchg_acquire(i32* %a) nounwind uwtable { entry: atomicrmw xchg i32* %a, i32 0 acquire @@ -850,6 +938,14 @@ entry: ; CHECK: atomic32_xor_acquire ; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 2) +define void @atomic32_nand_acquire(i32* %a) nounwind uwtable { +entry: + atomicrmw nand i32* %a, i32 0 acquire + ret void +} +; CHECK: atomic32_nand_acquire +; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 2) + define void @atomic32_xchg_release(i32* %a) nounwind uwtable { entry: atomicrmw xchg i32* %a, i32 0 release @@ -898,6 +994,14 @@ entry: ; CHECK: atomic32_xor_release ; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 3) +define void @atomic32_nand_release(i32* %a) nounwind uwtable { +entry: + atomicrmw nand i32* %a, i32 0 release + ret void +} +; CHECK: atomic32_nand_release +; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 3) + define void @atomic32_xchg_acq_rel(i32* %a) nounwind uwtable { entry: atomicrmw xchg i32* %a, i32 0 acq_rel @@ -946,6 +1050,14 @@ entry: ; CHECK: atomic32_xor_acq_rel ; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 4) +define void @atomic32_nand_acq_rel(i32* %a) nounwind uwtable { +entry: + atomicrmw nand i32* %a, i32 0 acq_rel + ret void +} +; CHECK: atomic32_nand_acq_rel +; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 4) + define void @atomic32_xchg_seq_cst(i32* %a) nounwind uwtable { entry: atomicrmw xchg i32* %a, i32 0 seq_cst @@ -994,13 +1106,21 @@ entry: ; CHECK: atomic32_xor_seq_cst ; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 5) +define void @atomic32_nand_seq_cst(i32* %a) nounwind uwtable { +entry: + atomicrmw nand i32* %a, i32 0 seq_cst + ret void +} +; CHECK: atomic32_nand_seq_cst +; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 5) + define void @atomic32_cas_monotonic(i32* %a) nounwind uwtable { entry: cmpxchg i32* %a, i32 0, i32 1 monotonic ret void } ; CHECK: atomic32_cas_monotonic -; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0) +; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0, i32 0) define void @atomic32_cas_acquire(i32* %a) nounwind uwtable { entry: @@ -1008,7 +1128,7 @@ entry: ret void } ; CHECK: atomic32_cas_acquire -; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2) +; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2, i32 2) define void @atomic32_cas_release(i32* %a) nounwind uwtable { entry: @@ -1016,7 +1136,7 @@ entry: ret void } ; CHECK: atomic32_cas_release -; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3) +; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3, i32 0) define void @atomic32_cas_acq_rel(i32* %a) nounwind uwtable { entry: @@ -1024,7 +1144,7 @@ entry: ret void } ; CHECK: atomic32_cas_acq_rel -; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4) +; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4, i32 2) define void @atomic32_cas_seq_cst(i32* %a) nounwind uwtable { entry: @@ -1032,7 +1152,7 @@ entry: ret void } ; CHECK: atomic32_cas_seq_cst -; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5) +; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5, i32 5) define i64 @atomic64_load_unordered(i64* %a) nounwind uwtable { entry: @@ -1146,6 +1266,14 @@ entry: ; CHECK: atomic64_xor_monotonic ; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 0) +define void @atomic64_nand_monotonic(i64* %a) nounwind uwtable { +entry: + atomicrmw nand i64* %a, i64 0 monotonic + ret void +} +; CHECK: atomic64_nand_monotonic +; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 0) + define void @atomic64_xchg_acquire(i64* %a) nounwind uwtable { entry: atomicrmw xchg i64* %a, i64 0 acquire @@ -1194,6 +1322,14 @@ entry: ; CHECK: atomic64_xor_acquire ; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 2) +define void @atomic64_nand_acquire(i64* %a) nounwind uwtable { +entry: + atomicrmw nand i64* %a, i64 0 acquire + ret void +} +; CHECK: atomic64_nand_acquire +; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 2) + define void @atomic64_xchg_release(i64* %a) nounwind uwtable { entry: atomicrmw xchg i64* %a, i64 0 release @@ -1242,6 +1378,14 @@ entry: ; CHECK: atomic64_xor_release ; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 3) +define void @atomic64_nand_release(i64* %a) nounwind uwtable { +entry: + atomicrmw nand i64* %a, i64 0 release + ret void +} +; CHECK: atomic64_nand_release +; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 3) + define void @atomic64_xchg_acq_rel(i64* %a) nounwind uwtable { entry: atomicrmw xchg i64* %a, i64 0 acq_rel @@ -1290,6 +1434,14 @@ entry: ; CHECK: atomic64_xor_acq_rel ; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 4) +define void @atomic64_nand_acq_rel(i64* %a) nounwind uwtable { +entry: + atomicrmw nand i64* %a, i64 0 acq_rel + ret void +} +; CHECK: atomic64_nand_acq_rel +; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 4) + define void @atomic64_xchg_seq_cst(i64* %a) nounwind uwtable { entry: atomicrmw xchg i64* %a, i64 0 seq_cst @@ -1338,13 +1490,21 @@ entry: ; CHECK: atomic64_xor_seq_cst ; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 5) +define void @atomic64_nand_seq_cst(i64* %a) nounwind uwtable { +entry: + atomicrmw nand i64* %a, i64 0 seq_cst + ret void +} +; CHECK: atomic64_nand_seq_cst +; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 5) + define void @atomic64_cas_monotonic(i64* %a) nounwind uwtable { entry: cmpxchg i64* %a, i64 0, i64 1 monotonic ret void } ; CHECK: atomic64_cas_monotonic -; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0) +; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0, i32 0) define void @atomic64_cas_acquire(i64* %a) nounwind uwtable { entry: @@ -1352,7 +1512,7 @@ entry: ret void } ; CHECK: atomic64_cas_acquire -; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2) +; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2, i32 2) define void @atomic64_cas_release(i64* %a) nounwind uwtable { entry: @@ -1360,7 +1520,7 @@ entry: ret void } ; CHECK: atomic64_cas_release -; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3) +; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3, i32 0) define void @atomic64_cas_acq_rel(i64* %a) nounwind uwtable { entry: @@ -1368,7 +1528,7 @@ entry: ret void } ; CHECK: atomic64_cas_acq_rel -; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4) +; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4, i32 2) define void @atomic64_cas_seq_cst(i64* %a) nounwind uwtable { entry: @@ -1376,7 +1536,7 @@ entry: ret void } ; CHECK: atomic64_cas_seq_cst -; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5) +; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 5) define i128 @atomic128_load_unordered(i128* %a) nounwind uwtable { entry: @@ -1490,6 +1650,14 @@ entry: ; CHECK: atomic128_xor_monotonic ; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 0) +define void @atomic128_nand_monotonic(i128* %a) nounwind uwtable { +entry: + atomicrmw nand i128* %a, i128 0 monotonic + ret void +} +; CHECK: atomic128_nand_monotonic +; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 0) + define void @atomic128_xchg_acquire(i128* %a) nounwind uwtable { entry: atomicrmw xchg i128* %a, i128 0 acquire @@ -1538,6 +1706,14 @@ entry: ; CHECK: atomic128_xor_acquire ; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 2) +define void @atomic128_nand_acquire(i128* %a) nounwind uwtable { +entry: + atomicrmw nand i128* %a, i128 0 acquire + ret void +} +; CHECK: atomic128_nand_acquire +; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 2) + define void @atomic128_xchg_release(i128* %a) nounwind uwtable { entry: atomicrmw xchg i128* %a, i128 0 release @@ -1586,6 +1762,14 @@ entry: ; CHECK: atomic128_xor_release ; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 3) +define void @atomic128_nand_release(i128* %a) nounwind uwtable { +entry: + atomicrmw nand i128* %a, i128 0 release + ret void +} +; CHECK: atomic128_nand_release +; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 3) + define void @atomic128_xchg_acq_rel(i128* %a) nounwind uwtable { entry: atomicrmw xchg i128* %a, i128 0 acq_rel @@ -1634,6 +1818,14 @@ entry: ; CHECK: atomic128_xor_acq_rel ; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 4) +define void @atomic128_nand_acq_rel(i128* %a) nounwind uwtable { +entry: + atomicrmw nand i128* %a, i128 0 acq_rel + ret void +} +; CHECK: atomic128_nand_acq_rel +; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 4) + define void @atomic128_xchg_seq_cst(i128* %a) nounwind uwtable { entry: atomicrmw xchg i128* %a, i128 0 seq_cst @@ -1682,13 +1874,21 @@ entry: ; CHECK: atomic128_xor_seq_cst ; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 5) +define void @atomic128_nand_seq_cst(i128* %a) nounwind uwtable { +entry: + atomicrmw nand i128* %a, i128 0 seq_cst + ret void +} +; CHECK: atomic128_nand_seq_cst +; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 5) + define void @atomic128_cas_monotonic(i128* %a) nounwind uwtable { entry: cmpxchg i128* %a, i128 0, i128 1 monotonic ret void } ; CHECK: atomic128_cas_monotonic -; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 0) +; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 0, i32 0) define void @atomic128_cas_acquire(i128* %a) nounwind uwtable { entry: @@ -1696,7 +1896,7 @@ entry: ret void } ; CHECK: atomic128_cas_acquire -; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 2) +; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 2, i32 2) define void @atomic128_cas_release(i128* %a) nounwind uwtable { entry: @@ -1704,7 +1904,7 @@ entry: ret void } ; CHECK: atomic128_cas_release -; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 3) +; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 3, i32 0) define void @atomic128_cas_acq_rel(i128* %a) nounwind uwtable { entry: @@ -1712,7 +1912,7 @@ entry: ret void } ; CHECK: atomic128_cas_acq_rel -; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 4) +; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 4, i32 2) define void @atomic128_cas_seq_cst(i128* %a) nounwind uwtable { entry: @@ -1720,7 +1920,7 @@ entry: ret void } ; CHECK: atomic128_cas_seq_cst -; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 5) +; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 5, i32 5) define void @atomic_signal_fence_acquire() nounwind uwtable { entry: diff --git a/test/Instrumentation/ThreadSanitizer/read_from_global.ll b/test/Instrumentation/ThreadSanitizer/read_from_global.ll index a08453ac4a94a..7b6b94edf1b1c 100644 --- a/test/Instrumentation/ThreadSanitizer/read_from_global.ll +++ b/test/Instrumentation/ThreadSanitizer/read_from_global.ll @@ -48,7 +48,7 @@ entry: } ; CHECK: define void @call_virtual_func -; CHECK: __tsan_read +; CHECK: __tsan_vptr_read ; CHECK: = load ; CHECK-NOT: __tsan_read ; CHECK: = load diff --git a/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll b/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll new file mode 100644 index 0000000000000..a83a274bcf6e3 --- /dev/null +++ b/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -basicaa -gvn -tsan -S | FileCheck %s +; TSAN conflicts with load widening. Make sure the load widening is off with -tsan. + +; 32-bit little endian target. +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" + +%struct_of_8_bytes_4_aligned = type { i32, i8, i8, i8, i8} + +@f = global %struct_of_8_bytes_4_aligned zeroinitializer, align 4 + +; Accessing bytes 4 and 6, not ok to widen to i32 if sanitize_thread is set. + +define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone sanitize_thread { +entry: + %tmp = load i8* getelementptr inbounds (%struct_of_8_bytes_4_aligned* @f, i64 0, i32 1), align 4 + %conv = zext i8 %tmp to i32 + %tmp1 = load i8* getelementptr inbounds (%struct_of_8_bytes_4_aligned* @f, i64 0, i32 3), align 1 + %conv2 = zext i8 %tmp1 to i32 + %add = add nsw i32 %conv, %conv2 + ret i32 %add +; CHECK: @test_widening_bad +; CHECK: call void @__tsan_read1 +; CHECK: call void @__tsan_read1 +; CHECK-NOT: call void @__tsan_read4 +; CHECK: ret i32 +} diff --git a/test/Instrumentation/ThreadSanitizer/tsan_basic.ll b/test/Instrumentation/ThreadSanitizer/tsan_basic.ll index 33c703b4c9bd8..0ecff40493a24 100644 --- a/test/Instrumentation/ThreadSanitizer/tsan_basic.ll +++ b/test/Instrumentation/ThreadSanitizer/tsan_basic.ll @@ -20,3 +20,36 @@ entry: ; CHECK: ret i32 +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) +declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) + + +; Check that tsan converts mem intrinsics back to function calls. + +define void @MemCpyTest(i8* nocapture %x, i8* nocapture %y) { +entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %x, i8* %y, i64 16, i32 4, i1 false) + ret void +; CHECK: define void @MemCpyTest +; CHECK: call i8* @memcpy +; CHECK: ret void +} + +define void @MemMoveTest(i8* nocapture %x, i8* nocapture %y) { +entry: + tail call void @llvm.memmove.p0i8.p0i8.i64(i8* %x, i8* %y, i64 16, i32 4, i1 false) + ret void +; CHECK: define void @MemMoveTest +; CHECK: call i8* @memmove +; CHECK: ret void +} + +define void @MemSetTest(i8* nocapture %x) { +entry: + tail call void @llvm.memset.p0i8.i64(i8* %x, i8 77, i64 16, i32 4, i1 false) + ret void +; CHECK define void @MemSetTest +; CHECK: call i8* @memset +; CHECK: ret void +} diff --git a/test/Instrumentation/ThreadSanitizer/vptr_read.ll b/test/Instrumentation/ThreadSanitizer/vptr_read.ll new file mode 100644 index 0000000000000..404ca3ffe50f9 --- /dev/null +++ b/test/Instrumentation/ThreadSanitizer/vptr_read.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -tsan -S | FileCheck %s +; Check that vptr reads are treated in a special way. +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-S128" + +define i8 @Foo(i8* %a) nounwind uwtable { +entry: +; CHECK: call void @__tsan_vptr_read + %0 = load i8* %a, align 8, !tbaa !0 + ret i8 %0 +} +!0 = metadata !{metadata !"vtable pointer", metadata !1} +!1 = metadata !{metadata !"Simple C/C++ TBAA", null} + |
