[CodeGenObjC] Handle exceptions when calling objc_alloc or objc_allocWithZone
authorErik Pilkington <erik.pilkington@gmail.com>
Wed, 30 Jan 2019 23:17:38 +0000 (23:17 +0000)
committerErik Pilkington <erik.pilkington@gmail.com>
Wed, 30 Jan 2019 23:17:38 +0000 (23:17 +0000)
objc_alloc and objc_allocWithZone may throw exceptions if the
underlying method does. If we're in a @try block, then make sure we
emit an invoke instead of a call.

rdar://47610407

Differential revision: https://reviews.llvm.org/D57476

llvm-svn: 352687

clang/lib/CodeGen/CGObjC.cpp
clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m

index 3e64080..9a21296 100644 (file)
@@ -2022,7 +2022,8 @@ static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
                                            llvm::Value *value,
                                            llvm::Type *returnType,
                                            llvm::Constant *&fn,
-                                           StringRef fnName) {
+                                           StringRef fnName,
+                                           bool MayThrow) {
   if (isa<llvm::ConstantPointerNull>(value))
     return value;
 
@@ -2042,10 +2043,14 @@ static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
   value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
 
   // Call the function.
-  llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
+  llvm::CallBase *Inst = nullptr;
+  if (MayThrow)
+    Inst = CGF.EmitCallOrInvoke(fn, value);
+  else
+    Inst = CGF.EmitNounwindRuntimeCall(fn, value);
 
   // Cast the result back to the original type.
-  return CGF.Builder.CreateBitCast(call, origType);
+  return CGF.Builder.CreateBitCast(Inst, origType);
 }
 
 /// Produce the code to do a retain.  Based on the type, calls one of:
@@ -2493,7 +2498,7 @@ llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
                                             llvm::Type *resultType) {
   return emitObjCValueOperation(*this, value, resultType,
                                 CGM.getObjCEntrypoints().objc_alloc,
-                                "objc_alloc");
+                                "objc_alloc", /*MayThrow=*/true);
 }
 
 /// Allocate the given objc object.
@@ -2502,7 +2507,7 @@ llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value,
                                                     llvm::Type *resultType) {
   return emitObjCValueOperation(*this, value, resultType,
                                 CGM.getObjCEntrypoints().objc_allocWithZone,
-                                "objc_allocWithZone");
+                                "objc_allocWithZone", /*MayThrow=*/true);
 }
 
 /// Produce the code to do a primitive release.
@@ -2543,18 +2548,20 @@ void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
 ///   call i8* \@objc_autorelease(i8* %value)
 llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
                                                   llvm::Type *returnType) {
-  return emitObjCValueOperation(*this, value, returnType,
-                      CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
-                                "objc_autorelease");
+  return emitObjCValueOperation(
+      *this, value, returnType,
+      CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
+      "objc_autorelease", /*MayThrow=*/false);
 }
 
 /// Retain the given object, with normal retain semantics.
 ///   call i8* \@objc_retain(i8* %value)
 llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
                                                      llvm::Type *returnType) {
-  return emitObjCValueOperation(*this, value, returnType,
-                          CGM.getObjCEntrypoints().objc_retainRuntimeFunction,
-                                "objc_retain");
+  return emitObjCValueOperation(
+      *this, value, returnType,
+      CGM.getObjCEntrypoints().objc_retainRuntimeFunction, "objc_retain",
+      /*MayThrow=*/false);
 }
 
 /// Release the given object.
index 8ce024f..39a2647 100644 (file)
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
+// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
+// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
 // Note: This line below is for tvos for which the driver passes through to use the ios9.0 runtime.
-// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
+// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
 
 #define nil (id)0
 
@@ -38,6 +38,19 @@ void test1(id x) {
   [x autorelease];
 }
 
+// CHECK-LABEL: define {{.*}}void @check_invoke
+void check_invoke() {
+  // MSGS: {{invoke.*@objc_msgSend}}
+  // MSGS: {{invoke.*@objc_msgSend}}
+  // CALLS: {{invoke.*@objc_alloc}}
+  // CALLS: {{invoke.*@objc_allocWithZone}}
+  @try {
+    [NSObject alloc];
+    [NSObject allocWithZone:nil];
+  } @catch (...) {
+  }
+}
+
 // CHECK-LABEL: define {{.*}}void @test2
 void test2(void* x) {
   // MSGS: {{call.*@objc_msgSend}}