diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index b646127cfae7..204b0a6c468b 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -740,7 +740,7 @@ public: ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned() : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) - : RetEffect::MakeOwned(RetEffect::ObjC, true))), + : RetEffect::MakeOwned(RetEffect::ObjC))), ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) @@ -953,7 +953,10 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { // When the CGBitmapContext is deallocated, the callback here will free // the associated data buffer. - if (Name->isStr("CGBitmapContextCreateWithData")) + // The callback in dispatch_data_create frees the buffer, but not + // the data object. + if (Name->isStr("CGBitmapContextCreateWithData") || + Name->isStr("dispatch_data_create")) RE = S->getRetEffect(); } } @@ -1086,7 +1089,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { FName == "IOOpenFirmwarePathMatching") { // Part of <rdar://problem/6961230>. (IOKit) // This should be addressed using a API table. - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), DoNothing, DoNothing); } else if (FName == "IOServiceGetMatchingService" || FName == "IOServiceGetMatchingServices") { @@ -1116,7 +1119,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // passed to CGBitmapContextCreateWithData is released via // a callback and doing full IPA to make sure this is done correctly. ScratchArgs = AF.add(ScratchArgs, 8, StopTracking); - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), DoNothing, DoNothing); } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { // FIXES: <rdar://problem/7283567> @@ -1126,6 +1129,14 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // correctly. ScratchArgs = AF.add(ScratchArgs, 12, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } else if (FName == "VTCompressionSessionEncodeFrame") { + // The context argument passed to VTCompressionSessionEncodeFrame() + // is passed to the callback specified when creating the session + // (e.g. with VTCompressionSessionCreate()) which can release it. + // To account for this possibility, conservatively stop tracking + // the context. + ScratchArgs = AF.add(ScratchArgs, 5, StopTracking); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } else if (FName == "dispatch_set_context" || FName == "xpc_connection_set_context") { // <rdar://problem/11059275> - The analyzer currently doesn't have @@ -1171,8 +1182,9 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { break; } - // For CoreGraphics ('CG') types. - if (cocoa::isRefType(RetTy, "CG", FName)) { + // For CoreGraphics ('CG') and CoreVideo ('CV') types. + if (cocoa::isRefType(RetTy, "CG", FName) || + cocoa::isRefType(RetTy, "CV", FName)) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); else @@ -1283,7 +1295,7 @@ const RetainSummary * RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { assert (ScratchArgs.isEmpty()); - return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF)); } const RetainSummary * @@ -1313,7 +1325,7 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, } if (D->hasAttr<CFReturnsRetainedAttr>()) - return RetEffect::MakeOwned(RetEffect::CF, true); + return RetEffect::MakeOwned(RetEffect::CF); if (D->hasAttr<CFReturnsNotRetainedAttr>()) return RetEffect::MakeNotOwned(RetEffect::CF); @@ -1426,7 +1438,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, case OMF_new: case OMF_copy: case OMF_mutableCopy: - ResultEff = RetEffect::MakeOwned(RetEffect::CF, true); + ResultEff = RetEffect::MakeOwned(RetEffect::CF); break; default: ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); @@ -1448,7 +1460,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, if (cocoa::isCocoaObjectRef(RetTy)) ResultEff = ObjCAllocRetE; else if (coreFoundation::isCFObjectRef(RetTy)) - ResultEff = RetEffect::MakeOwned(RetEffect::CF, true); + ResultEff = RetEffect::MakeOwned(RetEffect::CF); break; case OMF_autorelease: ReceiverEff = Autorelease; @@ -1579,7 +1591,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { // The next methods are allocators. const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); const RetainSummary *CFAllocSumm = - getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); + getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF)); // Create the "retain" selector. RetEffect NoRet = RetEffect::MakeNoRet(); @@ -1978,11 +1990,23 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, } if (CurrV.getObjKind() == RetEffect::CF) { - os << " returns a Core Foundation object with a "; + if (Sym->getType().isNull()) { + os << " returns a Core Foundation object with a "; + } else { + os << " returns a Core Foundation object of type " + << Sym->getType().getAsString() << " with a "; + } } else { assert (CurrV.getObjKind() == RetEffect::ObjC); - os << " returns an Objective-C object with a "; + QualType T = Sym->getType(); + if (T.isNull() || !isa<ObjCObjectPointerType>(T)) { + os << " returns an Objective-C object with a "; + } else { + const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T); + os << " returns an instance of " + << PT->getPointeeType().getAsString() << " with a "; + } } if (CurrV.isOwned()) { @@ -2358,10 +2382,15 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, os << "that is annotated as NS_RETURNS_NOT_RETAINED"; else { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - os << "whose name ('" << MD->getSelector().getAsString() - << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'." - " This violates the naming convention rules" - " given in the Memory Management Guide for Cocoa"; + if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) { + os << "managed by Automatic Reference Counting"; + } else { + os << "whose name ('" << MD->getSelector().getAsString() + << "') does not start with " + "'copy', 'mutableCopy', 'alloc' or 'new'." + " This violates the naming convention rules" + " given in the Memory Management Guide for Cocoa"; + } } else { const FunctionDecl *FD = cast<FunctionDecl>(D); @@ -2417,12 +2446,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, // FIXME: This will crash the analyzer if an allocation comes from an // implicit call (ex: a destructor call). // (Currently there are no such allocations in Cocoa, though.) - const Stmt *AllocStmt = nullptr; - ProgramPoint P = AllocNode->getLocation(); - if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) - AllocStmt = Exit->getCalleeContext()->getCallSite(); - else - AllocStmt = P.castAs<PostStmt>().getStmt(); + const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); assert(AllocStmt && "Cannot find allocation statement"); PathDiagnosticLocation AllocLocation = @@ -2640,10 +2664,6 @@ public: ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const; - bool wantsRegionChangeUpdate(ProgramStateRef state) const { - return true; - } - void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, @@ -3071,7 +3091,6 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, // No work necessary. break; - case RetEffect::OwnedAllocatedSymbol: case RetEffect::OwnedSymbol: { SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); if (!Sym) @@ -3372,12 +3391,13 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // Handle: id NSMakeCollectable(CFTypeRef) canEval = II->isStr("NSMakeCollectable"); } else if (ResultTy->isPointerType()) { - // Handle: (CF|CG)Retain + // Handle: (CF|CG|CV)Retain // CFAutorelease // CFMakeCollectable // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist). if (cocoa::isRefType(ResultTy, "CF", FName) || - cocoa::isRefType(ResultTy, "CG", FName)) { + cocoa::isRefType(ResultTy, "CG", FName) || + cocoa::isRefType(ResultTy, "CV", FName)) { canEval = isRetain(FD, FName) || isAutorelease(FD, FName) || isMakeCollectable(FD, FName); } @@ -3866,7 +3886,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { // Don't process anything within synthesized bodies. const LocationContext *LCtx = Pred->getLocationContext(); if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) { - assert(LCtx->getParent()); + assert(!LCtx->inTopFrame()); return; } |