1; RUN: opt < %s -S -mcpu=z13 -passes=msan 2>&1 | FileCheck %s 2 3target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64" 4target triple = "s390x-unknown-linux-gnu" 5 6%struct.__va_list = type { i64, i64, ptr, ptr } 7 8define i64 @foo(i64 %guard, ...) { 9 %vl = alloca %struct.__va_list, align 8 10 call void @llvm.lifetime.start.p0(i64 32, ptr %vl) 11 call void @llvm.va_start(ptr %vl) 12 call void @llvm.va_end(ptr %vl) 13 call void @llvm.lifetime.end.p0(i64 32, ptr %vl) 14 ret i64 0 15} 16 17; First check if the variadic shadow values are saved in stack with correct 18; size (which is 160 - size of the register save area). 19 20; CHECK-LABEL: @foo 21; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls 22; CHECK: [[B:%.*]] = add i64 160, [[A]] 23; CHECK: alloca {{.*}} [[B]] 24 25; We expect two memcpy operations: one for the register save area, and one for 26; the overflow arg area. 27 28; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 {{%.*}}, i64 160, i1 false) 29; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 {{%.*}}, i64 [[A]], i1 false) 30 31declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1 32declare void @llvm.va_start(ptr) #2 33declare void @llvm.va_end(ptr) #2 34declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 35 36declare i32 @random_i32() 37declare i64 @random_i64() 38declare float @random_float() 39declare double @random_double() 40 41define i64 @bar() { 42 %arg2 = call i32 () @random_i32() 43 %arg3 = call float () @random_float() 44 %arg4 = call i32 () @random_i32() 45 %arg5 = call double () @random_double() 46 %arg6 = call i64 () @random_i64() 47 %arg9 = call i32 () @random_i32() 48 %arg11 = call float () @random_float() 49 %arg12 = call i32 () @random_i32() 50 %arg13 = call double () @random_double() 51 %arg14 = call i64 () @random_i64() 52 %1 = call i64 (i64, ...) @foo(i64 1, i32 zeroext %arg2, float %arg3, 53 i32 signext %arg4, double %arg5, i64 %arg6, 54 i64 7, double 8.0, i32 zeroext %arg9, 55 double 10.0, float %arg11, i32 signext %arg12, 56 double %arg13, i64 %arg14) 57 ret i64 %1 58} 59 60; Save the incoming shadow values from the varargs in the __msan_va_arg_tls 61; array at the offsets equal to those defined by the ABI for the corresponding 62; registers in the register save area, and for the corresponding overflow args 63; in the overflow arg area: 64; - r2@16 == i64 1 - skipped, because it's fixed 65; - r3@24 == i32 zext %arg2 - shadow is zero-extended 66; - f0@128 == float %arg3 - left-justified, shadow is 32-bit 67; - r4@32 == i32 sext %arg4 - shadow is sign-extended 68; - f2@136 == double %arg5 - straightforward 69; - r5@40 == i64 %arg6 - straightforward 70; - r6@48 == 7 - filler 71; - f4@144 == 8.0 - filler 72; - overflow@160 == i32 zext %arg9 - shadow is zero-extended 73; - f6@152 == 10.0 - filler 74; - overflow@(168 + 4) == float %arg11 - right-justified, shadow is 32-bit 75; - overflow@176 == i32 sext %arg12 - shadow is sign-extended 76; - overflow@184 == double %arg13 - straightforward 77; - overflow@192 == i64 %arg14 - straightforward 78; Overflow arg area size is 40. 79 80; CHECK-LABEL: @bar 81 82; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24 83; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 128 84; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32 85; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 136 86; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 40 87; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 48 88; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 144 89; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160 90; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 152 91; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 172 92; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 176 93; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 184 94; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 192 95; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls 96 97; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are 98; passed to a variadic function. 99 100define dso_local i64 @many_args() { 101entry: 102 %ret = call i64 (i64, ...) @sum(i64 120, 103 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 104 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 105 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 106 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 107 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 108 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 109 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 110 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 111 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 112 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 113 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, 114 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1 115 ) 116 ret i64 %ret 117} 118 119; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed. 120; CHECK-LABEL: @many_args 121; CHECK: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 792) 122; CHECK-NOT: i64 add (i64 ptrtoint (ptr @__msan_va_arg_tls to i64), i64 800) 123 124declare i64 @sum(i64 %n, ...) 125 126; Test offset calculation for vector arguments. 127; Regardless of whether or not fixed args overflow, we should copy a shadow 128; for a single vector vararg to offset 160. 129 130declare void @vr_no_overflow(<4 x float> %v24, <4 x float> %v26, 131 <4 x float> %v28, <4 x float> %v30, 132 <4 x float> %v25, <4 x float> %v27, 133 <4 x float> %v29, ...) 134 135declare <4 x float> @vr_value() 136 137define void @vr_no_overflow_caller() { 138 %1 = call <4 x float> () @vr_value() 139 call void (<4 x float>, <4 x float>, <4 x float>, 140 <4 x float>, <4 x float>, <4 x float>, 141 <4 x float>, ...) @vr_no_overflow( 142 <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1, 143 <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1) 144 ret void 145} 146 147; CHECK-LABEL: @vr_no_overflow_caller 148; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160 149; CHECK-NOT: store {{.*}} @__msan_va_arg_tls {{.*}} 150; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls 151 152declare void @vr_overflow(<4 x float> %v24, <4 x float> %v26, 153 <4 x float> %v28, <4 x float> %v30, 154 <4 x float> %v25, <4 x float> %v27, 155 <4 x float> %v29, <4 x float> %v31, 156 <4 x float> %overflow, ...) 157 158define void @vr_overflow_caller() { 159 %1 = call <4 x float> @vr_value() 160 call void (<4 x float>, <4 x float>, <4 x float>, 161 <4 x float>, <4 x float>, <4 x float>, 162 <4 x float>, <4 x float>, <4 x float>, 163 ...) @vr_overflow( 164 <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1, 165 <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1, 166 <4 x float> %1, <4 x float> %1) 167 ret void 168} 169 170; CHECK-LABEL: @vr_overflow_caller 171; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160 172; CHECK-NOT: store {{.*}} @__msan_va_arg_tls {{.*}} 173; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls 174 175; Test that i128 and fp128 are passed by reference. 176 177declare i128 @random_i128() 178declare fp128 @random_fp128() 179 180define i64 @bar_128() { 181 %iarg = call i128 @random_i128() 182 %fparg = call fp128 @random_fp128() 183 %1 = call i64 (i64, ...) @foo(i64 1, i128 %iarg, fp128 %fparg) 184 ret i64 %1 185} 186 187; CHECK-LABEL: @bar_128 188; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24 189; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32 190; CHECK: store {{.*}} 0, {{.*}} @__msan_va_arg_overflow_size_tls 191 192; CHECK: declare void @__msan_maybe_warning_1(i8 zeroext, i32 zeroext) 193; CHECK: declare void @__msan_maybe_store_origin_1(i8 zeroext, ptr, i32 zeroext) 194; CHECK: declare void @__msan_maybe_warning_2(i16 zeroext, i32 zeroext) 195; CHECK: declare void @__msan_maybe_store_origin_2(i16 zeroext, ptr, i32 zeroext) 196; CHECK: declare void @__msan_maybe_warning_4(i32 zeroext, i32 zeroext) 197; CHECK: declare void @__msan_maybe_store_origin_4(i32 zeroext, ptr, i32 zeroext) 198; CHECK: declare void @__msan_maybe_warning_8(i64 zeroext, i32 zeroext) 199; CHECK: declare void @__msan_maybe_store_origin_8(i64 zeroext, ptr, i32 zeroext) 200 201; Test vararg function pointers. 202; 203; void (*ptr)(int, ...); 204; void call_ptr(void) { ptr(0); } 205 206@ptr = dso_local global ptr null, align 8 207 208define dso_local void @call_ptr() { 209 %1 = load ptr, ptr @ptr, align 8 210 call void (i32, ...) %1(i32 noundef signext 0) 211 ret void 212} 213