diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 03956bb293..ab8acb1831 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -930,6 +930,35 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, S = getPersistentSummary(RE, RecEffect, DefEffect); } + + // Special case '[super init];' and '[self init];' + // + // Even though calling '[super init]' without assigning the result to self + // and checking if the parent returns 'nil' is a bad pattern, it is common. + // Additionally, our Self Init checker already warns about it. To avoid + // overwhelming the user with messages from both checkers, we model the case + // of '[super init]' in cases when it is not consumed by another expression + // as if the call preserves the value of 'self'; essentially, assuming it can + // never fail and return 'nil'. + // Note, we don't want to just stop tracking the value since we want the + // RetainCount checker to report leaks and use-after-free if SelfInit checker + // is turned off. + if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) { + if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) { + + // Check if the message is not consumed, we know it will not be used in + // an assignment, ex: "self = [super init]". + const Expr *ME = MC->getOriginExpr(); + const LocationContext *LCtx = MC->getLocationContext(); + ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap(); + if (!PM.isConsumedExpr(ME)) { + RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); + ModifiableSummaryTemplate->setReceiverEffect(DoNothing); + ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); + } + } + + } } const RetainSummary * |