diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2012-01-28 18:46:31 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2012-01-28 18:46:31 +0000 |
commit | de2fdc249e9c04757a7aaec029b231f4d7e6dbd7 (patch) | |
tree | 3bd7e701ef2f94c627b4de576e552d2e0c8c08bd /lib/CodeGen/CodeGenFunction.h | |
parent | a49a2839266f0bac2b6286e9f49fdc0c292938fe (diff) |
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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149184 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenFunction.h')
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index e105f31f0f..ef81087c3f 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2627,7 +2627,75 @@ template <> struct DominatingValue<RValue> { } }; +/// 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 |