| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128" | ||
| target triple = "mips64el--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check multiple fixed arguments. | ||
| declare i32 @foo2(i32 %g1, i32 %g2, ...) | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, i32, ...) @foo2(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store i64 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| ; RUN: opt < %s -S -msan-kernel=1 -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-i64:64-n32:64" | ||
| target triple = "powerpc64le--linux" | ||
|
|
||
| define void @Store1(ptr %p, i8 %x) sanitize_memory { | ||
| entry: | ||
| store i8 %x, ptr %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Store1( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_1(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: store i8 {{.+}}, ptr [[SHADOW]] | ||
| ; CHECK: ret void | ||
|
|
||
| define void @Store2(ptr %p, i16 %x) sanitize_memory { | ||
| entry: | ||
| store i16 %x, ptr %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Store2( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_2(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: store i16 {{.+}}, ptr [[SHADOW]] | ||
| ; CHECK: ret void | ||
|
|
||
| define void @Store4(ptr %p, i32 %x) sanitize_memory { | ||
| entry: | ||
| store i32 %x, ptr %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Store4( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_4(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: store i32 {{.+}}, ptr [[SHADOW]] | ||
| ; CHECK: ret void | ||
|
|
||
| define void @Store8(ptr %p, i64 %x) sanitize_memory { | ||
| entry: | ||
| store i64 %x, ptr %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Store8( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: store i64 {{.+}}, ptr [[SHADOW]] | ||
| ; CHECK: ret void | ||
|
|
||
| define void @Store16(ptr %p, i128 %x) sanitize_memory { | ||
| entry: | ||
| store i128 %x, ptr %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Store16( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_n(ptr %p, i64 16) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: store i128 {{.+}}, ptr [[SHADOW]] | ||
| ; CHECK: ret void | ||
|
|
||
| define i8 @Load1(ptr %p) sanitize_memory { | ||
| entry: | ||
| %0 = load i8, ptr %p | ||
| ret i8 %0 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Load1( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_1(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: [[SHADOW_VAL:%[a-z0-9_]+]] = load i8, ptr [[SHADOW]] | ||
| ; CHECK: [[ORIGIN_VAL:%[a-z0-9_]+]] = load i32, ptr [[ORIGIN]] | ||
| ; CHECK: store i8 [[SHADOW_VAL]], ptr %retval_shadow | ||
| ; CHECK: store i32 [[ORIGIN_VAL]], ptr %retval_origin | ||
| ; CHECK: ret i8 {{.+}} | ||
|
|
||
| define i16 @Load2(ptr %p) sanitize_memory { | ||
| entry: | ||
| %0 = load i16, ptr %p | ||
| ret i16 %0 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Load2( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_2(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: [[SHADOW_VAL:%[a-z0-9_]+]] = load i16, ptr [[SHADOW]] | ||
| ; CHECK: [[ORIGIN_VAL:%[a-z0-9_]+]] = load i32, ptr [[ORIGIN]] | ||
| ; CHECK: store i16 [[SHADOW_VAL]], ptr %retval_shadow | ||
| ; CHECK: store i32 [[ORIGIN_VAL]], ptr %retval_origin | ||
| ; CHECK: ret i16 {{.+}} | ||
|
|
||
| define i32 @Load4(ptr %p) sanitize_memory { | ||
| entry: | ||
| %0 = load i32, ptr %p | ||
| ret i32 %0 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Load4( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_4(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: [[SHADOW_VAL:%[a-z0-9_]+]] = load i32, ptr [[SHADOW]] | ||
| ; CHECK: [[ORIGIN_VAL:%[a-z0-9_]+]] = load i32, ptr [[ORIGIN]] | ||
| ; CHECK: store i32 [[SHADOW_VAL]], ptr %retval_shadow | ||
| ; CHECK: store i32 [[ORIGIN_VAL]], ptr %retval_origin | ||
| ; CHECK: ret i32 {{.+}} | ||
|
|
||
| define i64 @Load8(ptr %p) sanitize_memory { | ||
| entry: | ||
| %0 = load i64, ptr %p | ||
| ret i64 %0 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Load8( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_8(ptr %p) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: [[SHADOW_VAL:%[a-z0-9_]+]] = load i64, ptr [[SHADOW]] | ||
| ; CHECK: [[ORIGIN_VAL:%[a-z0-9_]+]] = load i32, ptr [[ORIGIN]] | ||
| ; CHECK: store i64 [[SHADOW_VAL]], ptr %retval_shadow | ||
| ; CHECK: store i32 [[ORIGIN_VAL]], ptr %retval_origin | ||
| ; CHECK: ret i64 {{.+}} | ||
|
|
||
| define i128 @Load16(ptr %p) sanitize_memory { | ||
| entry: | ||
| %0 = load i128, ptr %p | ||
| ret i128 %0 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: define {{[^@]+}}@Load16( | ||
| ; CHECK: [[META:%[a-z0-9_]+]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_n(ptr %p, i64 16) | ||
| ; CHECK: [[SHADOW:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 0 | ||
| ; CHECK: [[ORIGIN:%[a-z0-9_]+]] = extractvalue { ptr, ptr } [[META]], 1 | ||
| ; CHECK: [[SHADOW_VAL:%[a-z0-9_]+]] = load i128, ptr [[SHADOW]] | ||
| ; CHECK: [[ORIGIN_VAL:%[a-z0-9_]+]] = load i32, ptr [[ORIGIN]] | ||
| ; CHECK: store i128 [[SHADOW_VAL]], ptr %retval_shadow | ||
| ; CHECK: store i32 [[ORIGIN_VAL]], ptr %retval_origin | ||
| ; CHECK: ret i128 {{.+}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "E-m:e-i64:64-n32:64" | ||
| target triple = "powerpc64--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. The first argument is stored at position 4, since it's right | ||
| ; justified. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 4) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check vector argument. | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, <2 x i64> <i64 1, i64 2>) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; The vector is at offset 16 of parameter save area, but __msan_va_arg_tls | ||
| ; corresponds to offset 8+ of parameter save area - so the offset from | ||
| ; __msan_va_arg_tls is actually misaligned. | ||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store <2 x i64> zeroinitializer, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check i64 array. | ||
| define i32 @bar4() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64] [i64 1, i64 2]) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar4 | ||
| ; CHECK: store [2 x i64] zeroinitializer, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check i128 array. | ||
| define i32 @bar5() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, [2 x i128] [i128 1, i128 2]) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar5 | ||
| ; CHECK: store [2 x i128] zeroinitializer, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check 8-aligned byval. | ||
| define i32 @bar6(ptr %arg) { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, ptr byval([2 x i64]) align 8 %arg) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar6 | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 @__msan_va_arg_tls, ptr align 8 {{.*}}, i64 16, i1 false) | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check 16-aligned byval. | ||
| define i32 @bar7(ptr %arg) { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, ptr byval([4 x i64]) align 16 %arg) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar7 | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), ptr align 8 {{.*}}, i64 32, i1 false) | ||
| ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-i64:64-n32:64" | ||
| target triple = "powerpc64le--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check vector argument. | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, <2 x i64> <i64 1, i64 2>) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; The vector is at offset 16 of parameter save area, but __msan_va_arg_tls | ||
| ; corresponds to offset 8+ of parameter save area - so the offset from | ||
| ; __msan_va_arg_tls is actually misaligned. | ||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store <2 x i64> zeroinitializer, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check i64 array. | ||
| define i32 @bar4() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64] [i64 1, i64 2]) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar4 | ||
| ; CHECK: store [2 x i64] zeroinitializer, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check i128 array. | ||
| define i32 @bar5() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, [2 x i128] [i128 1, i128 2]) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar5 | ||
| ; CHECK: store [2 x i128] zeroinitializer, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check 8-aligned byval. | ||
| define i32 @bar6(ptr %arg) { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, ptr byval([2 x i64]) align 8 %arg) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar6 | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 @__msan_va_arg_tls, ptr align 8 {{.*}}, i64 16, i1 false) | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check 16-aligned byval. | ||
| define i32 @bar7(ptr %arg) { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, ptr byval([4 x i64]) align 16 %arg) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar7 | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), ptr align 8 {{.*}}, i64 32, i1 false) | ||
| ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| ; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s | ||
|
|
||
| target datalayout = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128" | ||
| target triple = "mips64--linux" | ||
|
|
||
| define i32 @foo(i32 %guard, ...) { | ||
| %vl = alloca ptr, align 8 | ||
| call void @llvm.lifetime.start.p0(i64 32, ptr %vl) | ||
| call void @llvm.va_start(ptr %vl) | ||
| call void @llvm.va_end(ptr %vl) | ||
| call void @llvm.lifetime.end.p0(i64 32, ptr %vl) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ; First, check allocation of the save area. | ||
|
|
||
| ; CHECK-LABEL: @foo | ||
| ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls | ||
| ; CHECK: [[B:%.*]] = add i64 0, [[A]] | ||
| ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]] | ||
|
|
||
| ; CHECK: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 [[B]], i1 false) | ||
|
|
||
| ; CHECK: [[D:%.*]] = call i64 @llvm.umin.i64(i64 [[B]], i64 800) | ||
| ; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C]], ptr align 8 @__msan_va_arg_tls, i64 [[D]], i1 false) | ||
|
|
||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
| declare void @llvm.va_start(ptr) #2 | ||
| declare void @llvm.va_end(ptr) #2 | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| define i32 @bar() { | ||
| %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls | ||
| ; array. The first argument is stored at position 4, since it's right | ||
| ; justified. | ||
| ; CHECK-LABEL: @bar | ||
| ; CHECK: store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 4) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 16) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Check multiple fixed arguments. | ||
| declare i32 @foo2(i32 %g1, i32 %g2, ...) | ||
| define i32 @bar2() { | ||
| %1 = call i32 (i32, i32, ...) @foo2(i32 0, i32 1, i64 2, double 3.000000e+00) | ||
| ret i32 %1 | ||
| } | ||
|
|
||
| ; CHECK-LABEL: @bar2 | ||
| ; CHECK: store i64 0, ptr @__msan_va_arg_tls, align 8 | ||
| ; CHECK: store i64 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 8) to ptr), align 8 | ||
| ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) | ||
|
|
||
| ; CHECK: declare void @__msan_maybe_warning_1(i8 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_1(i8 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_2(i16 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_2(i16 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_4(i32 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_4(i32 signext, ptr, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_warning_8(i64 signext, i32 signext) | ||
| ; CHECK: declare void @__msan_maybe_store_origin_8(i64 signext, ptr, i32 signext) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| ; Test for the conservative assembly handling mode used by KMSAN. | ||
| ; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0 \ | ||
| ; RUN: -msan-handle-asm-conservative=0 -S -passes=msan 2>&1 | FileCheck \ | ||
| ; RUN: "-check-prefix=CHECK" %s | ||
| ; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0 \ | ||
| ; RUN: -msan-handle-asm-conservative=1 -S -passes=msan 2>&1 | FileCheck \ | ||
| ; RUN: "-check-prefixes=CHECK,CHECK-CONS" %s | ||
|
|
||
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| ; The IR below was generated from the following source: | ||
| ; int main() { | ||
| ; bool bit; | ||
| ; unsigned long value = 2; | ||
| ; long nr = 0; | ||
| ; unsigned long *addr = &value; | ||
| ; asm("btsq %2, %1; setc %0" : "=qm" (bit), "=m" (addr): "Ir" (nr)); | ||
| ; if (bit) | ||
| ; return 0; | ||
| ; else | ||
| ; return 1; | ||
| ; } | ||
| ; | ||
| ; In the regular instrumentation mode MSan is unable to understand that |bit| | ||
| ; is initialized by the asm() call, and therefore reports a false positive on | ||
| ; the if-statement. | ||
| ; The conservative assembly handling mode initializes every memory location | ||
| ; passed by pointer into an asm() call. This prevents false positive reports, | ||
| ; but may introduce false negatives. | ||
| ; | ||
| ; This test makes sure that the conservative mode unpoisons the shadow of |bit| | ||
| ; by writing 0 to it. | ||
|
|
||
| define dso_local i32 @main() sanitize_memory { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %bit = alloca i8, align 1 | ||
| %value = alloca i64, align 8 | ||
| %nr = alloca i64, align 8 | ||
| %addr = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store i64 2, ptr %value, align 8 | ||
| store i64 0, ptr %nr, align 8 | ||
| store ptr %value, ptr %addr, align 8 | ||
| %0 = load i64, ptr %nr, align 8 | ||
| call void asm "btsq $2, $1; setc $0", "=*qm,=*m,Ir,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i8) %bit, ptr elementtype(ptr) %addr, i64 %0) | ||
| %1 = load i8, ptr %bit, align 1 | ||
| %tobool = trunc i8 %1 to i1 | ||
| br i1 %tobool, label %if.then, label %if.else | ||
|
|
||
| if.then: ; preds = %entry | ||
| ret i32 0 | ||
|
|
||
| if.else: ; preds = %entry | ||
| ret i32 1 | ||
| } | ||
|
|
||
| ; %nr is first poisoned, then unpoisoned (written to). Need to optimize this in the future. | ||
| ; CHECK: call void @__msan_poison_alloca(ptr %nr{{.*}}) | ||
| ; CHECK: call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr %nr) | ||
|
|
||
| ; Hooks for inputs usually go before the assembly statement. But here we have none, | ||
| ; because %nr is passed by value. However we check %nr for being initialized. | ||
| ; CHECK-CONS: call { ptr, ptr } @__msan_metadata_ptr_for_load_8(ptr %nr) | ||
|
|
||
| ; In the conservative mode, call the store hooks for %bit and %addr: | ||
| ; CHECK-CONS: call void @__msan_instrument_asm_store(ptr %bit, i64 1) | ||
| ; CHECK-CONS: call void @__msan_instrument_asm_store(ptr %addr, i64 8) | ||
|
|
||
| ; Landing pad for the %nr check above. | ||
| ; CHECK-CONS: call void @__msan_warning | ||
|
|
||
| ; CHECK: call void asm "btsq $2, $1; setc $0" | ||
|
|
||
| ; CHECK: [[META:%.*]] = call {{.*}} @__msan_metadata_ptr_for_load_1(ptr %bit) | ||
| ; CHECK: [[SHADOW:%.*]] = extractvalue { ptr, ptr } [[META]], 0 | ||
|
|
||
| ; Now load the shadow value for the boolean. | ||
| ; CHECK: [[MSLD:%.*]] = load {{.*}} [[SHADOW]] | ||
| ; CHECK: [[MSPROP:%.*]] = trunc i8 [[MSLD]] to i1 | ||
|
|
||
| ; Is the shadow poisoned? | ||
| ; CHECK: br i1 [[MSPROP]], label %[[IFTRUE:.*]], label {{.*}} | ||
|
|
||
| ; If yes, raise a warning. | ||
| ; CHECK: [[IFTRUE]]: | ||
| ; CHECK: call void @__msan_warning | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| ; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1 | FileCheck \ | ||
| ; RUN: %s | ||
| ; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=1 -S \ | ||
| ; RUN: -passes=msan 2>&1 | FileCheck -check-prefix=CHECK \ | ||
| ; RUN: -check-prefix=CHECK-ORIGINS %s | ||
| ; REQUIRES: x86-registered-target | ||
|
|
||
| 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" | ||
|
|
||
| ; Store intrinsic. | ||
|
|
||
| define void @StoreIntrinsic(ptr %p, <4 x float> %x) nounwind uwtable sanitize_memory { | ||
| call void @llvm.x86.sse.storeu.ps(ptr %p, <4 x float> %x) | ||
| ret void | ||
| } | ||
|
|
||
| declare void @llvm.x86.sse.storeu.ps(ptr, <4 x float>) nounwind | ||
|
|
||
| ; CHECK-LABEL: @StoreIntrinsic | ||
| ; CHECK-NOT: br | ||
| ; CHECK-NOT: = or | ||
| ; CHECK: store <4 x i32> {{.*}} align 1 | ||
| ; CHECK: store <4 x float> %{{.*}}, ptr %{{.*}}, align 1{{$}} | ||
| ; CHECK: ret void | ||
|
|
||
|
|
||
| ; Load intrinsic. | ||
|
|
||
| define <16 x i8> @LoadIntrinsic(ptr %p) nounwind uwtable sanitize_memory { | ||
| %call = call <16 x i8> @llvm.x86.sse3.ldu.dq(ptr %p) | ||
| ret <16 x i8> %call | ||
| } | ||
|
|
||
| declare <16 x i8> @llvm.x86.sse3.ldu.dq(ptr %p) nounwind | ||
|
|
||
| ; CHECK-LABEL: @LoadIntrinsic | ||
| ; CHECK: load <16 x i8>, ptr {{.*}} align 1 | ||
| ; CHECK-ORIGINS: [[ORIGIN:%[01-9a-z]+]] = load i32, ptr {{.*}} | ||
| ; 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-ORIGINS: store i32 {{.*}}[[ORIGIN]], ptr @__msan_retval_origin_tls | ||
| ; CHECK: 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> @Pmulhuw128(<8 x i16> %a, <8 x i16> %b) nounwind uwtable sanitize_memory { | ||
| %call = call <8 x i16> @llvm.x86.sse2.pmulhu.w(<8 x i16> %a, <8 x i16> %b) | ||
| ret <8 x i16> %call | ||
| } | ||
|
|
||
| declare <8 x i16> @llvm.x86.sse2.pmulhu.w(<8 x i16> %a, <8 x i16> %b) nounwind | ||
|
|
||
| ; CHECK-LABEL: @Pmulhuw128 | ||
| ; CHECK-NEXT: load <8 x i16>, ptr @__msan_param_tls | ||
| ; CHECK-ORIGINS: load i32, ptr @__msan_param_origin_tls | ||
| ; CHECK-NEXT: load <8 x i16>, ptr {{.*}} @__msan_param_tls | ||
| ; CHECK-ORIGINS: load i32, ptr {{.*}} @__msan_param_origin_tls | ||
| ; CHECK-NEXT: call void @llvm.donothing | ||
| ; CHECK-NEXT: = or <8 x i16> | ||
| ; CHECK-ORIGINS: = bitcast <8 x i16> {{.*}} to i128 | ||
| ; CHECK-ORIGINS-NEXT: = icmp ne i128 {{.*}}, 0 | ||
| ; CHECK-ORIGINS-NEXT: = select i1 {{.*}}, i32 {{.*}}, i32 | ||
| ; CHECK-NEXT: call <8 x i16> @llvm.x86.sse2.pmulhu.w | ||
| ; CHECK-NEXT: store <8 x i16> {{.*}} @__msan_retval_tls | ||
| ; CHECK-ORIGINS: store i32 {{.*}} @__msan_retval_origin_tls | ||
| ; CHECK-NEXT: ret <8 x i16> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ; RUN: opt < %s -msan-check-access-address=0 -S 2>&1 -passes=msan | FileCheck \ | ||
| ; RUN: %s | ||
|
|
||
| ; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are | ||
| ; passed to a variadic function. | ||
|
|
||
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| define dso_local i64 @many_args() { | ||
| entry: | ||
| %ret = call i64 (i64, ...) @sum(i64 120, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, | ||
| i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 | ||
| ) | ||
| ret i64 %ret | ||
| } | ||
|
|
||
| ; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. | ||
| ; CHECK-LABEL: @many_args | ||
| ; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) | ||
| ; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) | ||
| declare i64 @sum(i64 %n, ...) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| ; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1 | FileCheck \ | ||
| ; RUN: %s | ||
| ; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=1 -S \ | ||
| ; RUN: -passes=msan 2>&1 | FileCheck %s "--check-prefixes=CHECK,CHECK-ORIGIN" | ||
| ; RUN: opt < %s -msan-check-access-address=0 -S \ | ||
| ; RUN: -passes="msan<track-origins=1>" 2>&1 | FileCheck %s "--check-prefixes=CHECK,CHECK-ORIGIN" | ||
| ; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=2 -S \ | ||
| ; RUN: -passes=msan 2>&1 | FileCheck %s "--check-prefixes=CHECK,CHECK-ORIGIN" | ||
|
|
||
| ; Test that shadow and origin are stored for variadic function params. | ||
|
|
||
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| %struct.__va_list_tag = type { i32, i32, ptr, ptr } | ||
|
|
||
| define dso_local i32 @test(i32 %a, i32 %b, i32 %c) local_unnamed_addr { | ||
| entry: | ||
| %call = tail call i32 (i32, ...) @sum(i32 3, i32 %a, i32 %b, i32 %c) | ||
| ret i32 %call | ||
| } | ||
|
|
||
| ; CHECK: store i32 0, {{.*}} @__msan_param_tls {{.*}} i64 8 | ||
| ; CHECK: store i32 0, {{.*}} @__msan_param_tls {{.*}} i64 16 | ||
| ; CHECK: store i32 0, {{.*}} @__msan_param_tls {{.*}} i64 24 | ||
| ; CHECK: store i32 0, {{.*}} @__msan_va_arg_tls {{.*}} i64 8 | ||
| ; CHECK-ORIGIN: store i32 0, {{.*}} @__msan_va_arg_origin_tls {{.*}} i64 8 | ||
| ; CHECK: store i32 0, {{.*}} @__msan_va_arg_tls {{.*}} i64 16 | ||
| ; CHECK-ORIGIN: store i32 0, {{.*}} @__msan_va_arg_origin_tls {{.*}} i64 16 | ||
| ; CHECK: store i32 0, {{.*}} @__msan_va_arg_tls {{.*}} i64 24 | ||
| ; CHECK-ORIGIN: store i32 0, {{.*}} @__msan_va_arg_origin_tls {{.*}} i64 24 | ||
|
|
||
| define dso_local i32 @sum(i32 %n, ...) local_unnamed_addr #0 { | ||
| entry: | ||
| %args = alloca [1 x %struct.__va_list_tag], align 16 | ||
| call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %args) #2 | ||
| call void @llvm.va_start(ptr nonnull %args) | ||
| %cmp9 = icmp sgt i32 %n, 0 | ||
| br i1 %cmp9, label %for.body.lr.ph, label %for.end | ||
|
|
||
| ; CHECK: call void @llvm.memcpy.{{.*}} [[SHADOW_COPY:%[_0-9a-z]+]], {{.*}} @__msan_va_arg_tls | ||
| ; CHECK-ORIGIN: call void @llvm.memcpy{{.*}} [[ORIGIN_COPY:%[_0-9a-z]+]], {{.*}} @__msan_va_arg_origin_tls | ||
|
|
||
| ; CHECK: call void @llvm.va_start | ||
| ; CHECK: call void @llvm.memcpy.{{.*}}, {{.*}} [[SHADOW_COPY]], i{{.*}} [[REGSAVE:[0-9]+]] | ||
| ; CHECK-ORIGIN: call void @llvm.memcpy.{{.*}}, {{.*}} [[ORIGIN_COPY]], i{{.*}} [[REGSAVE]] | ||
|
|
||
| ; CHECK: [[OVERFLOW_SHADOW:%[_0-9a-z]+]] = getelementptr i8, ptr [[SHADOW_COPY]], i{{.*}} [[REGSAVE]] | ||
| ; CHECK: call void @llvm.memcpy.{{.*}}[[OVERFLOW_SHADOW]] | ||
| ; CHECK-ORIGIN: [[OVERFLOW_ORIGIN:%[_0-9a-z]+]] = getelementptr i8, ptr [[ORIGIN_COPY]], i{{.*}} [[REGSAVE]] | ||
| ; CHECK-ORIGIN: call void @llvm.memcpy.{{.*}}[[OVERFLOW_ORIGIN]] | ||
|
|
||
| for.body.lr.ph: ; preds = %entry | ||
| %0 = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %args, i64 0, i64 0, i32 3 | ||
| %overflow_arg_area_p = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %args, i64 0, i64 0, i32 2 | ||
| %gp_offset.pre = load i32, ptr %args, align 16 | ||
| br label %for.body | ||
|
|
||
| for.body: ; preds = %vaarg.end, %for.body.lr.ph | ||
| %gp_offset = phi i32 [ %gp_offset.pre, %for.body.lr.ph ], [ %gp_offset12, %vaarg.end ] | ||
| %sum.011 = phi i32 [ 0, %for.body.lr.ph ], [ %add, %vaarg.end ] | ||
| %i.010 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %vaarg.end ] | ||
| %fits_in_gp = icmp ult i32 %gp_offset, 41 | ||
| br i1 %fits_in_gp, label %vaarg.in_reg, label %vaarg.in_mem | ||
|
|
||
| vaarg.in_reg: ; preds = %for.body | ||
| %reg_save_area = load ptr, ptr %0, align 16 | ||
| %1 = sext i32 %gp_offset to i64 | ||
| %2 = getelementptr i8, ptr %reg_save_area, i64 %1 | ||
| %3 = add i32 %gp_offset, 8 | ||
| store i32 %3, ptr %args, align 16 | ||
| br label %vaarg.end | ||
|
|
||
| vaarg.in_mem: ; preds = %for.body | ||
| %overflow_arg_area = load ptr, ptr %overflow_arg_area_p, align 8 | ||
| %overflow_arg_area.next = getelementptr i8, ptr %overflow_arg_area, i64 8 | ||
| store ptr %overflow_arg_area.next, ptr %overflow_arg_area_p, align 8 | ||
| br label %vaarg.end | ||
|
|
||
| vaarg.end: ; preds = %vaarg.in_mem, %vaarg.in_reg | ||
| %gp_offset12 = phi i32 [ %3, %vaarg.in_reg ], [ %gp_offset, %vaarg.in_mem ] | ||
| %vaarg.addr.in = phi ptr [ %2, %vaarg.in_reg ], [ %overflow_arg_area, %vaarg.in_mem ] | ||
| %4 = load i32, ptr %vaarg.addr.in, align 4 | ||
| %add = add nsw i32 %4, %sum.011 | ||
| %inc = add nuw nsw i32 %i.010, 1 | ||
| %exitcond = icmp eq i32 %inc, %n | ||
| br i1 %exitcond, label %for.end, label %for.body | ||
|
|
||
| for.end: ; preds = %vaarg.end, %entry | ||
| %sum.0.lcssa = phi i32 [ 0, %entry ], [ %add, %vaarg.end ] | ||
| call void @llvm.va_end(ptr nonnull %args) | ||
| call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %args) #2 | ||
| ret i32 %sum.0.lcssa | ||
| } | ||
|
|
||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 | ||
|
|
||
| ; Function Attrs: nounwind | ||
| declare void @llvm.va_start(ptr) #2 | ||
|
|
||
| ; Function Attrs: nounwind | ||
| declare void @llvm.va_end(ptr) #2 | ||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 | ||
|
|
||
| declare dso_local i80 @sum_i80(i32, ...) local_unnamed_addr | ||
|
|
||
| ; Unaligned types like i80 should also work. | ||
| define dso_local i80 @test_i80(i80 %a, i80 %b, i80 %c) local_unnamed_addr { | ||
| entry: | ||
| %call = tail call i80 (i32, ...) @sum_i80(i32 3, i80 %a, i80 %b, i80 %c) | ||
| ret i80 %call | ||
| } | ||
|
|