diff options
| author | Aaron Ballman <aaron@aaronballman.com> | 2014-08-28 16:48:44 +0000 |
|---|---|---|
| committer | Aaron Ballman <aaron@aaronballman.com> | 2014-08-28 16:48:44 +0000 |
| commit | 33375375a4c31cf31803c6f9555ca023864818fe (patch) | |
| tree | f8e4e3072f6693adc5dce78cf2a499134ecb2bd8 /clang/lib/CodeGen | |
| parent | 50cbfc513827b192b77f3c2ee5ea70fcda36433e (diff) | |
| download | bcm5719-llvm-33375375a4c31cf31803c6f9555ca023864818fe.tar.gz bcm5719-llvm-33375375a4c31cf31803c6f9555ca023864818fe.zip | |
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.
llvm-svn: 216675
Diffstat (limited to 'clang/lib/CodeGen')
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 7 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 35 |
4 files changed, 58 insertions, 7 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 55ddd666c49..bdd887c4a02 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/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/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 39813fd475d..af5fb19f256 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/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/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index db876b11694..1d175b25816 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/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/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5df3e43f488..8034e1e5b9b 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/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, |

