From: Aaron Ballman Date: Thu, 28 Aug 2014 16:48:44 +0000 (+0000) Subject: Throw a std::bad_array_new_length exception when the expression (or constant-expressi... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c990380ce6984649f98d6bfea7543fa9e24f37b;p=clang Throw a std::bad_array_new_length exception when the expression (or constant-expression) passed to operator new[] results in overflow in conformance with [expr.new]p7. Fixes PR11644. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216675 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 55ddd666c4..bdd887c4a0 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -325,3 +325,12 @@ LValue CGCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) { return false; } + +llvm::Value *CGCXXABI::EmitNewArrayLengthOverflowCheck( + CodeGenFunction &CGF, bool ConstantOverflow, llvm::Value *DynamicOverflow, + llvm::Value *Size) { + llvm::Value *AllOnes = llvm::Constant::getAllOnesValue(CGF.SizeTy); + if (ConstantOverflow) + return AllOnes; + return CGF.Builder.CreateSelect(DynamicOverflow, AllOnes, Size); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 39813fd475..af5fb19f25 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -236,6 +236,13 @@ public: virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0; + /// Emit the code required to throw a std::bad_array_new_length exception by + /// the ABI, and returns the array length size to allocate. + virtual llvm::Value * + EmitNewArrayLengthOverflowCheck(CodeGenFunction &CGF, bool ConstantOverflow, + llvm::Value *DynamicOverflow, + llvm::Value *Size); + virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This, const CXXRecordDecl *ClassDecl, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index db876b1169..1d175b2581 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -572,11 +572,11 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, } // On overflow, produce a -1 so operator new will fail. - if (hasAnyOverflow) { - size = llvm::Constant::getAllOnesValue(CGF.SizeTy); - } else { + if (hasAnyOverflow) + size = CGF.CGM.getCXXABI().EmitNewArrayLengthOverflowCheck( + CGF, true, nullptr, llvm::Constant::getAllOnesValue(CGF.SizeTy)); + else size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize); - } // Otherwise, we might need to use the overflow intrinsics. } else { @@ -714,9 +714,9 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, // overwrite 'size' with an all-ones value, which should cause // operator new to throw. if (hasOverflow) - size = CGF.Builder.CreateSelect(hasOverflow, - llvm::Constant::getAllOnesValue(CGF.SizeTy), - size); + size = CGF.CGM.getCXXABI().EmitNewArrayLengthOverflowCheck(CGF, false, + hasOverflow, + size); } if (cookieSize == 0) diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 5df3e43f48..8034e1e5b9 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -133,6 +133,11 @@ public: bool EmitBadCastCall(CodeGenFunction &CGF) override; + llvm::Value *EmitNewArrayLengthOverflowCheck(CodeGenFunction &CGF, + bool ConstantOverflow, + llvm::Value *DynamicOverflow, + llvm::Value *Size) override; + llvm::Value * GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This, const CXXRecordDecl *ClassDecl, @@ -1044,6 +1049,36 @@ bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) { return true; } +llvm::Value *ItaniumCXXABI::EmitNewArrayLengthOverflowCheck( + CodeGenFunction &CGF, bool ConstantOverflow, llvm::Value *DynamicOverflow, + llvm::Value *Size) { + // In C++11 and later, an overflow results in throwing + // std::bad_array_new_length. + if (!CGF.getLangOpts().CPlusPlus11) + return CGCXXABI::EmitNewArrayLengthOverflowCheck(CGF, ConstantOverflow, + DynamicOverflow, Size); + + llvm::BasicBlock *BadArrayNewLengthBlock = + CGF.createBasicBlock("new.bad_array_new_length"); + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("new.end"); + + if (!ConstantOverflow) { + assert(DynamicOverflow && "Called for dynamic case, but no overflow value"); + CGF.Builder.CreateCondBr(DynamicOverflow, BadArrayNewLengthBlock, EndBlock); + } + CGF.EmitBlock(BadArrayNewLengthBlock); + + // void __cxa_bad_array_new_length(); + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false); + llvm::Value *Fn = + CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_array_new_length"); + CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn(); + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(EndBlock); + return Size; +} + llvm::Value * ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This, diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp index 65123ea7fe..da11710bdd 100644 --- a/test/CodeGenCXX/new-array-init.cpp +++ b/test/CodeGenCXX/new-array-init.cpp @@ -14,7 +14,12 @@ void fn(int n) { // CHECK-LABEL: define void @_Z15const_underflowv void const_underflow() { // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 - // CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1) + // CHECK: br label %[[BAD:.*]] + // CHECK: [[BAD]]: + // CHECK-NEXT: call void @__cxa_bad_array_new_length() + // CHECK-NEXT: unreachable + // CHECK: {{.*}}: + // CHECK: ret void new int[2] { 1, 2, 3 }; } diff --git a/test/CodeGenCXX/operator-new.cpp b/test/CodeGenCXX/operator-new.cpp index db56cda6cd..2844241f33 100644 --- a/test/CodeGenCXX/operator-new.cpp +++ b/test/CodeGenCXX/operator-new.cpp @@ -1,8 +1,7 @@ -// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-llvm -o %t-1.ll %s -// RUN: FileCheck -check-prefix SANE --input-file=%t-1.ll %s -// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-llvm -fno-assume-sane-operator-new -o %t-2.ll %s -// RUN: FileCheck -check-prefix SANENOT --input-file=%t-2.ll %s - +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -std=c++98 -emit-llvm -o - %s | FileCheck -check-prefix SANE98 %s +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -std=c++11 -emit-llvm -o - %s | FileCheck -check-prefix SANE11 %s +// RUN: %clang_cc1 -triple i686-pc-win32-msvc -std=c++11 -emit-llvm -o - %s | FileCheck -check-prefix SANE11MS %s +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-llvm -fno-assume-sane-operator-new -o - %s | FileCheck -check-prefix SANENOT %s class teste { int A; @@ -20,10 +19,44 @@ void f1() { // rdar://5739832 - operator new should check for overflow in multiply. void *f2(long N) { return new int[N]; - -// SANE: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow -// SANE-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1 -// SANE-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0 -// SANE-NEXT: [[RESULT:%.*]] = select i1 [[OVER]], i32 -1, i32 [[SUM]] -// SANE-NEXT: call noalias i8* @_Znaj(i32 [[RESULT]]) + +// SANE98: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow +// SANE98-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1 +// SANE98-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0 +// SANE98-NEXT: [[RESULT:%.*]] = select i1 [[OVER]], i32 -1, i32 [[SUM]] +// SANE98-NEXT: call noalias i8* @_Znaj(i32 [[RESULT]]) + +// SANE11: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow +// SANE11-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1 +// SANE11-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0 +// SANE11-NEXT: br i1 [[OVER]], label %[[BAD:.*]], label %[[GOOD:.*]] +// SANE11: [[BAD]]: +// SANE11-NEXT: call void @__cxa_bad_array_new_length() +// SANE11-NEXT: unreachable +// SANE11: [[GOOD]]: +// SANE11-NEXT: call noalias i8* @_Znaj(i32 [[SUM]]) + +// FIXME: There should be a call to generate the std::bad_array_new_length +// exception in the Microsoft ABI, however, this is not implemented currently. +// SANE11MS: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow +// SANE11MS-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1 +// SANE11MS-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0 +// SANE11MS-NEXT: [[RESULT:%.*]] = select i1 [[OVER]], i32 -1, i32 [[SUM]] +// SANE11MS-NEXT: call noalias i8* @"\01??_U@YAPAXI@Z"(i32 [[RESULT]]) +} + +#if __cplusplus > 199711L +void *f3() { + return new int[0x7FFFFFFF]; +// SANE11: br label %[[BAD:.*]] +// SANE11: [[BAD]]: +// SANE11-NEXT: call void @__cxa_bad_array_new_length() +// SANE11-NEXT: unreachable +// SANE11: {{.*}}: +// SANE11-NEXT: call noalias i8* @_Znaj(i32 -1) + +// FIXME: There should be a call to generate the std::bad_array_new_length +// exception in the Microsoft ABI, however, this is not implemented currently. +// SANE11MS: call noalias i8* @"\01??_U@YAPAXI@Z"(i32 -1) } +#endif