r216675 - 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.

Aaron Ballman aaron at aaronballman.com
Thu Aug 28 09:48:44 PDT 2014


Author: aaronballman
Date: Thu Aug 28 11:48:44 2014
New Revision: 216675

URL: http://llvm.org/viewvc/llvm-project?rev=216675&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/new-array-init.cpp
    cfe/trunk/test/CodeGenCXX/operator-new.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Thu Aug 28 11:48:44 2014
@@ -325,3 +325,12 @@ LValue CGCXXABI::EmitThreadLocalVarDeclL
 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);
+}

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Thu Aug 28 11:48:44 2014
@@ -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,

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Aug 28 11:48:44 2014
@@ -572,11 +572,11 @@ static llvm::Value *EmitCXXNewAllocSize(
     }
 
     // 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(
     // 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)

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Aug 28 11:48:44 2014
@@ -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(Code
   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,

Modified: cfe/trunk/test/CodeGenCXX/new-array-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new-array-init.cpp?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/new-array-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/new-array-init.cpp Thu Aug 28 11:48:44 2014
@@ -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 };
 }
 

Modified: cfe/trunk/test/CodeGenCXX/operator-new.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/operator-new.cpp?rev=216675&r1=216674&r2=216675&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/operator-new.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/operator-new.cpp Thu Aug 28 11:48:44 2014
@@ -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 at 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 at YAPAXI@Z"(i32 -1)
 }
+#endif





More information about the cfe-commits mailing list