From ac23fcdc321d9bf08d00697849ebbbdf850ecef6 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Thu, 6 Sep 2018 08:21:54 +0000 Subject: [PATCH] [MSan] Make sure variadic function arguments do not overflow __msan_va_arg_tls Turns out that calling a variadic function with too many (e.g. >100 i64's) arguments overflows __msan_va_arg_tls, which leads to smashing other TLS data with function argument shadow values. getShadow() already checks for kParamTLSSize and returns clean shadow if the argument does not fit, so just skip storing argument shadow for such arguments. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@341525 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Instrumentation/MemorySanitizer.cpp | 73 +++++++++++++++------- .../MemorySanitizer/AArch64/vararg.ll | 27 ++++++++ .../MemorySanitizer/Mips/vararg-mips64.ll | 27 ++++++++ .../MemorySanitizer/Mips/vararg-mips64el.ll | 27 ++++++++ .../MemorySanitizer/PowerPC/vararg-ppc64.ll | 28 +++++++++ .../MemorySanitizer/PowerPC/vararg-ppc64le.ll | 27 ++++++++ .../MemorySanitizer/X86/vararg-too-large.ll | 33 ++++++++++ 7 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 test/Instrumentation/MemorySanitizer/X86/vararg-too-large.ll diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 194d77c00ab..b3c31f5d53b 100644 --- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -3318,9 +3318,11 @@ struct VarArgAMD64Helper : public VarArgHelper { assert(A->getType()->isPointerTy()); Type *RealTy = A->getType()->getPointerElementType(); uint64_t ArgSize = DL.getTypeAllocSize(RealTy); - Value *ShadowBase = - getShadowPtrForVAArgument(RealTy, IRB, OverflowOffset); + Value *ShadowBase = getShadowPtrForVAArgument( + RealTy, IRB, OverflowOffset, alignTo(ArgSize, 8)); OverflowOffset += alignTo(ArgSize, 8); + if (!ShadowBase) + continue; Value *ShadowPtr, *OriginPtr; std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment, @@ -3337,11 +3339,13 @@ struct VarArgAMD64Helper : public VarArgHelper { Value *ShadowBase; switch (AK) { case AK_GeneralPurpose: - ShadowBase = getShadowPtrForVAArgument(A->getType(), IRB, GpOffset); + ShadowBase = + getShadowPtrForVAArgument(A->getType(), IRB, GpOffset, 8); GpOffset += 8; break; case AK_FloatingPoint: - ShadowBase = getShadowPtrForVAArgument(A->getType(), IRB, FpOffset); + ShadowBase = + getShadowPtrForVAArgument(A->getType(), IRB, FpOffset, 16); FpOffset += 16; break; case AK_Memory: @@ -3349,13 +3353,15 @@ struct VarArgAMD64Helper : public VarArgHelper { continue; uint64_t ArgSize = DL.getTypeAllocSize(A->getType()); ShadowBase = - getShadowPtrForVAArgument(A->getType(), IRB, OverflowOffset); + getShadowPtrForVAArgument(A->getType(), IRB, OverflowOffset, 8); OverflowOffset += alignTo(ArgSize, 8); } // Take fixed arguments into account for GpOffset and FpOffset, // but don't actually store shadows for them. if (IsFixed) continue; + if (!ShadowBase) + continue; IRB.CreateAlignedStore(MSV.getShadow(A), ShadowBase, kShadowTLSAlignment); } @@ -3367,7 +3373,10 @@ struct VarArgAMD64Helper : public VarArgHelper { /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, - int ArgOffset) { + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), @@ -3483,9 +3492,11 @@ struct VarArgMIPS64Helper : public VarArgHelper { if (ArgSize < 8) VAArgOffset += (8 - ArgSize); } - Base = getShadowPtrForVAArgument(A->getType(), IRB, VAArgOffset); + Base = getShadowPtrForVAArgument(A->getType(), IRB, VAArgOffset, ArgSize); VAArgOffset += ArgSize; VAArgOffset = alignTo(VAArgOffset, 8); + if (!Base) + continue; IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); } @@ -3497,7 +3508,10 @@ struct VarArgMIPS64Helper : public VarArgHelper { /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, - int ArgOffset) { + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), @@ -3628,11 +3642,11 @@ struct VarArgAArch64Helper : public VarArgHelper { Value *Base; switch (AK) { case AK_GeneralPurpose: - Base = getShadowPtrForVAArgument(A->getType(), IRB, GrOffset); + Base = getShadowPtrForVAArgument(A->getType(), IRB, GrOffset, 8); GrOffset += 8; break; case AK_FloatingPoint: - Base = getShadowPtrForVAArgument(A->getType(), IRB, VrOffset); + Base = getShadowPtrForVAArgument(A->getType(), IRB, VrOffset, 8); VrOffset += 16; break; case AK_Memory: @@ -3641,7 +3655,8 @@ struct VarArgAArch64Helper : public VarArgHelper { if (IsFixed) continue; uint64_t ArgSize = DL.getTypeAllocSize(A->getType()); - Base = getShadowPtrForVAArgument(A->getType(), IRB, OverflowOffset); + Base = getShadowPtrForVAArgument(A->getType(), IRB, OverflowOffset, + alignTo(ArgSize, 8)); OverflowOffset += alignTo(ArgSize, 8); break; } @@ -3649,6 +3664,8 @@ struct VarArgAArch64Helper : public VarArgHelper { // bother to actually store a shadow. if (IsFixed) continue; + if (!Base) + continue; IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); } Constant *OverflowSize = @@ -3658,7 +3675,10 @@ struct VarArgAArch64Helper : public VarArgHelper { /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, - int ArgOffset) { + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), @@ -3863,14 +3883,17 @@ struct VarArgPowerPC64Helper : public VarArgHelper { ArgAlign = 8; VAArgOffset = alignTo(VAArgOffset, ArgAlign); if (!IsFixed) { - Value *Base = getShadowPtrForVAArgument(RealTy, IRB, - VAArgOffset - VAArgBase); - Value *AShadowPtr, *AOriginPtr; - std::tie(AShadowPtr, AOriginPtr) = MSV.getShadowOriginPtr( - A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment, /*isStore*/ false); - - IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr, - kShadowTLSAlignment, ArgSize); + Value *Base = getShadowPtrForVAArgument( + RealTy, IRB, VAArgOffset - VAArgBase, ArgSize); + if (Base) { + Value *AShadowPtr, *AOriginPtr; + std::tie(AShadowPtr, AOriginPtr) = + MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), + kShadowTLSAlignment, /*isStore*/ false); + + IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr, + kShadowTLSAlignment, ArgSize); + } } VAArgOffset += alignTo(ArgSize, 8); } else { @@ -3898,8 +3921,9 @@ struct VarArgPowerPC64Helper : public VarArgHelper { } if (!IsFixed) { Base = getShadowPtrForVAArgument(A->getType(), IRB, - VAArgOffset - VAArgBase); - IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); + VAArgOffset - VAArgBase, ArgSize); + if (Base) + IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); } VAArgOffset += ArgSize; VAArgOffset = alignTo(VAArgOffset, 8); @@ -3917,7 +3941,10 @@ struct VarArgPowerPC64Helper : public VarArgHelper { /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, - int ArgOffset) { + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), diff --git a/test/Instrumentation/MemorySanitizer/AArch64/vararg.ll b/test/Instrumentation/MemorySanitizer/AArch64/vararg.ll index 8e8019c0c97..08387f8d1e9 100644 --- a/test/Instrumentation/MemorySanitizer/AArch64/vararg.ll +++ b/test/Instrumentation/MemorySanitizer/AArch64/vararg.ll @@ -74,3 +74,30 @@ define i32 @bar() { ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 56 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 192 ; CHECK: store {{.*}} 8, {{.*}} @__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: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) diff --git a/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64.ll b/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64.ll index 9948a001dd8..1463070ad85 100644 --- a/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64.ll +++ b/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64.ll @@ -53,3 +53,30 @@ define i32 @bar2() { ; CHECK: store i64 0, i64* getelementptr inbounds ([100 x i64], [100 x i64]* @__msan_va_arg_tls, i32 0, i32 0), align 8 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to i64*), 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 ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) diff --git a/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64el.ll b/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64el.ll index 3ca00ca120a..9edcb3666f2 100644 --- a/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64el.ll +++ b/test/Instrumentation/MemorySanitizer/Mips/vararg-mips64el.ll @@ -52,3 +52,30 @@ define i32 @bar2() { ; CHECK: store i64 0, i64* getelementptr inbounds ([100 x i64], [100 x i64]* @__msan_va_arg_tls, i32 0, i32 0), align 8 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to i64*), 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 ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) diff --git a/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64.ll b/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64.ll index fe10f0e45a9..5a2686900e9 100644 --- a/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64.ll +++ b/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64.ll @@ -111,3 +111,31 @@ define i32 @bar7([4 x i64]* %arg) { ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [4 x i64]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [4 x i64]*) ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[SHADOW]], i8* 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 ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) diff --git a/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64le.ll b/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64le.ll index 0c78cc2f4b4..c139d62c4f2 100644 --- a/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64le.ll +++ b/test/Instrumentation/MemorySanitizer/PowerPC/vararg-ppc64le.ll @@ -95,3 +95,30 @@ define i32 @bar7([4 x i64]* %arg) { ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [4 x i64]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [4 x i64]*) ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[SHADOW]], i8* 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 ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) diff --git a/test/Instrumentation/MemorySanitizer/X86/vararg-too-large.ll b/test/Instrumentation/MemorySanitizer/X86/vararg-too-large.ll new file mode 100644 index 00000000000..800bd15f124 --- /dev/null +++ b/test/Instrumentation/MemorySanitizer/X86/vararg-too-large.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -msan -msan-check-access-address=0 -S 2>&1 | FileCheck %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 ([100 x i64]* @__msan_va_arg_tls to i64), i64 792) +; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800) +declare i64 @sum(i64 %n, ...) -- 2.11.0