103 lines · plain
1; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s2 3target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"4target triple = "aarch64-unknown-linux-gnu"5 6%struct.__va_list = type { ptr, ptr, ptr, i32, i32 }7 8define i32 @foo(i32 %guard, ...) {9 %vl = alloca %struct.__va_list, align 810 call void @llvm.lifetime.start.p0(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(ptr %vl)14 ret i32 015}16 17; First check if the variadic shadow values are saved in stack with correct18; size (192 is total of general purpose registers size, 64, plus total of19; floating-point registers size, 128).20 21; CHECK-LABEL: @foo22; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls23; CHECK: [[B:%.*]] = add i64 192, [[A]]24; CHECK: alloca {{.*}} [[B]]25 26; We expect three memcpy operations: one for the general purpose registers,27; one for floating-point/SIMD ones, and one for thre remaining arguments.28 29; Propagate the GR shadow values on for the va_list::__gp_top, adjust the 30; offset in the __msan_va_arg_tls based on va_list:__gp_off, and finally31; issue the memcpy.32; CHECK: [[GRP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i64 {{%.*}}33; CHECK: [[GRSIZE:%.*]] = sub i64 64, {{%.*}}34; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 [[GRP]], i64 [[GRSIZE]], i1 false)35 36; Propagate the VR shadow values on for the va_list::__vr_top, adjust the 37; offset in the __msan_va_arg_tls based on va_list:__vr_off, and finally38; issue the memcpy.39; CHECK: [[VRP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i64 {{%.*}}40; CHECK: [[VRSIZE:%.*]] = sub i64 128, {{%.*}}41; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 [[VRP]], i64 [[VRSIZE]], i1 false)42 43; Copy the remaining shadow values on the va_list::__stack position (it is44; on the constant offset of 192 from __msan_va_arg_tls).45; CHECK: [[STACK:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i32 19246; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 {{%.*}}, ptr align 16 [[STACK]], i64 {{%.*}}, i1 false)47 48declare void @llvm.lifetime.start.p0(ptr nocapture) #149declare void @llvm.va_start(ptr) #250declare void @llvm.va_end(ptr) #251declare void @llvm.lifetime.end.p0(ptr nocapture) #152 53define i32 @bar() {54 %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i32 2, double 3.000000e+00, 55 double 4.000000e+00, i32 5, i32 6,56 double 7.000000e+00, i32 8, i32 9, i32 10, i32 11)57 ret i32 %158}59 60; Save the incoming shadow value from the arguments in the __msan_va_arg_tls61; array. General purpose registers are saved at positions from 0 to 64, Floating62; point and SIMD are saved from 64 to 192, and the remaining from 192.63; CHECK-LABEL: @bar64; CHECK: store {{.*}} @__msan_va_arg_tls, i64 865; CHECK: store {{.*}} @__msan_va_arg_tls, i64 1666; CHECK: store {{.*}} @__msan_va_arg_tls, i64 6467; CHECK: store {{.*}} @__msan_va_arg_tls, i64 8068; CHECK: store {{.*}} @__msan_va_arg_tls, i64 2469; CHECK: store {{.*}} @__msan_va_arg_tls, i64 3270; CHECK: store {{.*}} @__msan_va_arg_tls, i64 9671; CHECK: store {{.*}} @__msan_va_arg_tls, i64 4072; CHECK: store {{.*}} @__msan_va_arg_tls, i64 4873; CHECK: store {{.*}} @__msan_va_arg_tls, i64 5674; CHECK: store {{.*}} @__msan_va_arg_tls, i64 19275; CHECK: store {{.*}} 8, {{.*}} @__msan_va_arg_overflow_size_tls76 77; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are78; passed to a variadic function.79 80define dso_local i64 @many_args() {81entry:82 %ret = call i64 (i64, ...) @sum(i64 120,83 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,84 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,85 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,86 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,87 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,88 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,89 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,90 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,91 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,92 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,93 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,94 i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 195 )96 ret i64 %ret97}98 99; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed.100; CHECK: getelementptr (i8, ptr @__msan_va_arg_tls, i64 792)101; CHECK-NOT: getelementptr (i8, ptr @__msan_va_arg_tls, i64 800)102declare i64 @sum(i64 %n, ...)103