[cfe-commits] r149184 - in /cfe/trunk: lib/CodeGen/CGObjC.cpp lib/CodeGen/CGObjCMac.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenObjC/arc.m
Fariborz Jahanian
fjahanian at apple.com
Sat Jan 28 10:46:31 PST 2012
Author: fjahanian
Date: Sat Jan 28 12:46:31 2012
New Revision: 149184
URL: http://llvm.org/viewvc/llvm-project?rev=149184&view=rev
Log:
objc-arc: Perform null check on receiver before sending methods which
consume one or more of their arguments. If not done, this will cause a leak
as method will not consume the argument when receiver is null.
// rdar://10444474
Modified:
cfe/trunk/lib/CodeGen/CGObjC.cpp
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenObjC/arc.m
Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=149184&r1=149183&r2=149184&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Sat Jan 28 12:46:31 2012
@@ -136,7 +136,7 @@
bool isDelegateInit = E->isDelegateInitCall();
const ObjCMethodDecl *method = E->getMethodDecl();
-
+
// We don't retain the receiver in delegate init calls, and this is
// safe because the receiver value is always loaded from 'self',
// which we zero out. We don't want to Block_copy block receivers,
@@ -191,6 +191,19 @@
break;
}
+ // Check to see if receiver must be null checked before method is sent
+ // to the receiver.
+ NullReturnState nullReturn;
+ if (CGM.getLangOptions().ObjCAutoRefCount && method)
+ for (ObjCMethodDecl::param_const_iterator i = method->param_begin(),
+ e = method->param_end(); i != e; ++i) {
+ const ParmVarDecl *ParamDecl = (*i);
+ if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+ nullReturn.init(*this, Receiver);
+ break;
+ }
+ }
+
if (retainSelf)
Receiver = EmitARCRetainNonBlock(Receiver);
@@ -262,8 +275,8 @@
Builder.CreateStore(newSelf, selfAddr);
}
-
- return AdjustRelatedResultType(*this, E, method, result);
+ RValue rvalue = AdjustRelatedResultType(*this, E, method, result);
+ return nullReturn.complete(*this, rvalue, ResultType);
}
namespace {
@@ -292,6 +305,7 @@
method);
}
};
+
}
/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=149184&r1=149183&r2=149184&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Sat Jan 28 12:46:31 2012
@@ -1392,63 +1392,6 @@
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
};
-
-/// A helper class for performing the null-initialization of a return
-/// value.
-struct NullReturnState {
- llvm::BasicBlock *NullBB;
- llvm::BasicBlock *callBB;
- NullReturnState() : NullBB(0), callBB(0) {}
-
- void init(CodeGenFunction &CGF, llvm::Value *receiver) {
- // Make blocks for the null-init and call edges.
- NullBB = CGF.createBasicBlock("msgSend.nullinit");
- callBB = CGF.createBasicBlock("msgSend.call");
-
- // Check for a null receiver and, if there is one, jump to the
- // null-init test.
- llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
- CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
-
- // Otherwise, start performing the call.
- CGF.EmitBlock(callBB);
- }
-
- RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
- if (!NullBB) return result;
-
- // Finish the call path.
- llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
- if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
-
- // Emit the null-init block and perform the null-initialization there.
- CGF.EmitBlock(NullBB);
- if (!resultType->isAnyComplexType()) {
- assert(result.isAggregate() && "null init of non-aggregate result?");
- CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
- // Jump to the continuation block.
- CGF.EmitBlock(contBB);
- return result;
- }
-
- // _Complex type
- // FIXME. Now easy to handle any other scalar type whose result is returned
- // in memory due to ABI limitations.
- CGF.EmitBlock(contBB);
- CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
- llvm::Type *MemberType = CallCV.first->getType();
- llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
- // Create phi instruction for scalar complex value.
- llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
- PHIReal->addIncoming(ZeroCV, NullBB);
- PHIReal->addIncoming(CallCV.first, callBB);
- llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
- PHIImag->addIncoming(ZeroCV, NullBB);
- PHIImag->addIncoming(CallCV.second, callBB);
- return RValue::getComplex(PHIReal, PHIImag);
- }
-};
-
} // end anonymous namespace
/* *** Helper Functions *** */
@@ -1655,7 +1598,23 @@
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
- if (!IsSuper) nullReturn.init(CGF, Arg0);
+ if (!IsSuper) {
+ bool nullCheckAlreadyDone = false;
+ // We have already done this computation once and flag could have been
+ // passed down. But such cases are extremely rare and we do this lazily,
+ // instead of absorbing cost of passing down a flag for all cases.
+ if (CGM.getLangOptions().ObjCAutoRefCount && Method)
+ for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
+ e = Method->param_end(); i != e; ++i) {
+ if ((*i)->hasAttr<NSConsumedAttr>()) {
+ nullCheckAlreadyDone = true;
+ break;
+ }
+ }
+ if (!nullCheckAlreadyDone)
+ nullReturn.init(CGF, Arg0);
+ }
+
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=149184&r1=149183&r2=149184&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sat Jan 28 12:46:31 2012
@@ -2627,7 +2627,75 @@
}
};
+/// A helper class for performing the null-initialization of a return
+/// value.
+struct NullReturnState {
+ llvm::BasicBlock *NullBB;
+ llvm::BasicBlock *callBB;
+ NullReturnState() : NullBB(0), callBB(0) {}
+
+ void init(CodeGenFunction &CGF, llvm::Value *receiver) {
+ // Make blocks for the null-init and call edges.
+ NullBB = CGF.createBasicBlock("msgSend.nullinit");
+ callBB = CGF.createBasicBlock("msgSend.call");
+
+ // Check for a null receiver and, if there is one, jump to the
+ // null-init test.
+ llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
+ CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
+
+ // Otherwise, start performing the call.
+ CGF.EmitBlock(callBB);
+ }
+
+ RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
+ if (!NullBB) return result;
+
+ llvm::Value *NullInitPtr = 0;
+ if (result.isScalar() && !resultType->isVoidType()) {
+ NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType());
+ CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr);
+ }
+ // Finish the call path.
+ llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
+ if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
+
+ // Emit the null-init block and perform the null-initialization there.
+ CGF.EmitBlock(NullBB);
+ if (result.isScalar()) {
+ if (NullInitPtr)
+ CGF.EmitNullInitialization(NullInitPtr, resultType);
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+ return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr))
+ : result;
+ }
+
+ if (!resultType->isAnyComplexType()) {
+ assert(result.isAggregate() && "null init of non-aggregate result?");
+ CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+ return result;
+ }
+
+ // _Complex type
+ // FIXME. Now easy to handle any other scalar type whose result is returned
+ // in memory due to ABI limitations.
+ CGF.EmitBlock(contBB);
+ CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
+ llvm::Type *MemberType = CallCV.first->getType();
+ llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
+ // Create phi instruction for scalar complex value.
+ llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
+ PHIReal->addIncoming(ZeroCV, NullBB);
+ PHIReal->addIncoming(CallCV.first, callBB);
+ llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
+ PHIImag->addIncoming(ZeroCV, NullBB);
+ PHIImag->addIncoming(CallCV.second, callBB);
+ return RValue::getComplex(PHIReal, PHIImag);
+ }
+};
} // end namespace CodeGen
} // end namespace clang
-
#endif
Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=149184&r1=149183&r2=149184&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Sat Jan 28 12:46:31 2012
@@ -1500,12 +1500,16 @@
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST66]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST66]]*
-// CHECK-NEXT: [[T4:%.*]] = call i8* @test66_arg()
+// CHECK-NEXT: [[THREE:%.*]] = icmp eq [[TEST23:%.*]]* [[T3]], null
+// CHECK-NEXT: br i1 [[THREE]], label [[NULINIT:%.*]], label [[MSGCALL:%.*]]
+// CHECK: [[T4:%.*]] = call i8* @test66_arg()
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
// CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
-// CHECK-NEXT: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
+// CHECK-NEXT: br label [[MSGCONT:%.*]]
+// CHECK: br label [[MSGCONT:%.*]]
+// CHECK: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T8]])
// CHECK-NEXT: ret void
More information about the cfe-commits
mailing list