[cfe-commits] r149279 - in /cfe/trunk: lib/CodeGen/CGObjCMac.cpp test/CodeGenObjC/arc.m
Fariborz Jahanian
fjahanian at apple.com
Mon Jan 30 13:40:38 PST 2012
Author: fjahanian
Date: Mon Jan 30 15:40:37 2012
New Revision: 149279
URL: http://llvm.org/viewvc/llvm-project?rev=149279&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.
In this patch, the null path releases consumed argument.
// rdar://10444474
Modified:
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/test/CodeGenObjC/arc.m
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=149279&r1=149278&r2=149279&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Mon Jan 30 15:40:37 2012
@@ -1414,8 +1414,16 @@
CGF.EmitBlock(callBB);
}
- RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
+ RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
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");
@@ -1423,6 +1431,31 @@
// Emit the null-init block and perform the null-initialization there.
CGF.EmitBlock(NullBB);
+
+ // Release consumed arguments along the null-receiver path.
+ if (Method) {
+ CallArgList::const_iterator I = CallArgs.begin();
+ for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
+ e = Method->param_end(); i != e; ++i, ++I) {
+ const ParmVarDecl *ParamDecl = (*i);
+ if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+ RValue RV = I->RV;
+ assert(RV.isScalar() &&
+ "NullReturnState::complete - arg not on object");
+ CGF.EmitARCRelease(RV.getScalarVal(), true);
+ }
+ }
+ }
+
+ 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);
@@ -1668,9 +1701,24 @@
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
+
+ bool requiresnullCheck = false;
+ 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>()) {
+ if (!nullReturn.NullBB)
+ nullReturn.init(CGF, Arg0);
+ requiresnullCheck = true;
+ break;
+ }
+ }
+
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
- return nullReturn.complete(CGF, rvalue, ResultType);
+ return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
+ requiresnullCheck ? Method : 0);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
@@ -5785,7 +5833,8 @@
llvm::PointerType::getUnqual(fnType));
RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, result, resultType);
+ CallArgList CallArgs;
+ return nullReturn.complete(CGF, result, resultType, CallArgs, 0);
}
/// Generate code for a message send expression in the nonfragile abi.
Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=149279&r1=149278&r2=149279&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Mon Jan 30 15:40:37 2012
@@ -1489,8 +1489,13 @@
// 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: [[SIX:%.*]] = icmp eq i8* [[T7]], null
+// CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]]
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
+// CHECK-NEXT: br label [[CONT:%.*]]
+// CHECK: call void @objc_release(i8* [[T5]]) nounwind
+// CHECK-NEXT: br label [[CONT:%.*]]
+// 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