diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp | 87 | ||||
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h | 14 |
2 files changed, 57 insertions, 44 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index de113bbd057..e5d27f577d1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -814,12 +814,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { return true; } -//===----------------------------------------------------------------------===// -// Handle return statements. -//===----------------------------------------------------------------------===// - -void RetainCountChecker::checkPreStmt(const ReturnStmt *S, - CheckerContext &C) const { +ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S, + CheckerContext &C) const { + ExplodedNode *Pred = C.getPredecessor(); // Only adjust the reference count if this is the top-level call frame, // and not the result of inlining. In the future, we should do @@ -827,22 +824,25 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, // with their expected semantics (e.g., the method should return a retained // object, etc.). if (!C.inTopFrame()) - return; + return Pred; + + if (!S) + return Pred; const Expr *RetE = S->getRetValue(); if (!RetE) - return; + return Pred; ProgramStateRef state = C.getState(); SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol(); if (!Sym) - return; + return Pred; // Get the reference count binding (if any). const RefVal *T = getRefBinding(state, Sym); if (!T) - return; + return Pred; // Change the reference count. RefVal X = *T; @@ -861,20 +861,19 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, if (cnt) { X.setCount(cnt - 1); X = X ^ RefVal::ReturnedOwned; - } - else { + } else { X = X ^ RefVal::ReturnedNotOwned; } break; } default: - return; + return Pred; } // Update the binding. state = setRefBinding(state, Sym, X); - ExplodedNode *Pred = C.addTransition(state); + Pred = C.addTransition(state); // At this point we have updated the state properly. // Everything after this is merely checking to see if the return value has @@ -882,15 +881,15 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, // Did we cache out? if (!Pred) - return; + return nullptr; // Update the autorelease counts. static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease"); - state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X); + state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S); - // Did we cache out? + // Have we generated a sink node? if (!state) - return; + return nullptr; // Get the updated binding. T = getRefBinding(state, Sym); @@ -913,10 +912,10 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, } } - checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); + return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); } -void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, +ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, @@ -929,20 +928,17 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, // [self addSubview:_contentView]; // invalidates 'self' // [_contentView release]; if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) - return; + return Pred; // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { if (RE.getKind() != RetEffect::NoRet) { - bool hasError = false; if (!RE.isOwned()) { + // The returning type is a CF, we expect the enclosing method should // return ownership. - hasError = true; X = X ^ RefVal::ErrorLeakReturned; - } - if (hasError) { // Generate an error node. state = setRefBinding(state, Sym, X); @@ -950,10 +946,12 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag); if (N) { const LangOptions &LOpts = C.getASTContext().getLangOpts(); - C.emitReport(llvm::make_unique<CFRefLeakReport>( + auto R = llvm::make_unique<CFRefLeakReport>( *getLeakAtReturnBug(LOpts), LOpts, SummaryLog, N, Sym, C, - IncludeAllocationLine)); + IncludeAllocationLine); + C.emitReport(std::move(R)); } + return N; } } } else if (X.isReturnedNotOwned()) { @@ -977,13 +975,16 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, if (!returnNotOwnedForOwned) returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned(this)); - C.emitReport(llvm::make_unique<CFRefReport>( + auto R = llvm::make_unique<CFRefReport>( *returnNotOwnedForOwned, C.getASTContext().getLangOpts(), - SummaryLog, N, Sym)); + SummaryLog, N, Sym); + C.emitReport(std::move(R)); } + return N; } } } + return Pred; } //===----------------------------------------------------------------------===// @@ -1107,16 +1108,14 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state, return state; } -//===----------------------------------------------------------------------===// -// Handle dead symbols and end-of-path. -//===----------------------------------------------------------------------===// - ProgramStateRef RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, const ProgramPointTag *Tag, CheckerContext &Ctx, - SymbolRef Sym, RefVal V) const { + SymbolRef Sym, + RefVal V, + const ReturnStmt *S) const { unsigned ACnt = V.getAutoreleaseCount(); // No autorelease counts? Nothing to be done. @@ -1141,10 +1140,11 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, if (ACnt <= Cnt) { if (ACnt == Cnt) { V.clearCounts(); - if (V.getKind() == RefVal::ReturnedOwned) + if (V.getKind() == RefVal::ReturnedOwned) { V = V ^ RefVal::ReturnedNotOwned; - else + } else { V = V ^ RefVal::NotOwned; + } } else { V.setCount(V.getCount() - ACnt); V.setAutoreleaseCount(0); @@ -1181,8 +1181,9 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, overAutorelease.reset(new OverAutorelease(this)); const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); - Ctx.emitReport(llvm::make_unique<CFRefReport>( - *overAutorelease, LOpts, SummaryLog, N, Sym, os.str())); + auto R = llvm::make_unique<CFRefReport>(*overAutorelease, LOpts, SummaryLog, + N, Sym, os.str()); + Ctx.emitReport(std::move(R)); } return nullptr; @@ -1281,9 +1282,15 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { void RetainCountChecker::checkEndFunction(const ReturnStmt *RS, CheckerContext &Ctx) const { - ProgramStateRef state = Ctx.getState(); + ExplodedNode *Pred = processReturn(RS, Ctx); + + // Created state cached out. + if (!Pred) { + return; + } + + ProgramStateRef state = Pred->getState(); RefBindingsTy B = state->get<RefBindings>(); - ExplodedNode *Pred = Ctx.getPredecessor(); // Don't process anything within synthesized bodies. const LocationContext *LCtx = Pred->getLocationContext(); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h index 8683b23dd96..e8d9136ffd2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h @@ -252,7 +252,6 @@ class RetainCountChecker check::PostStmt<ObjCBoxedExpr>, check::PostStmt<ObjCIvarRefExpr>, check::PostCall, - check::PreStmt<ReturnStmt>, check::RegionChanges, eval::Assume, eval::Call > { @@ -388,8 +387,7 @@ public: const LocationContext* LCtx, const CallEvent *Call) const; - void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; - void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, + ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, SymbolRef Sym, ProgramStateRef state) const; @@ -416,12 +414,20 @@ public: ProgramStateRef handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, const ProgramPointTag *Tag, CheckerContext &Ctx, - SymbolRef Sym, RefVal V) const; + SymbolRef Sym, + RefVal V, + const ReturnStmt *S=nullptr) const; ExplodedNode *processLeaks(ProgramStateRef state, SmallVectorImpl<SymbolRef> &Leaked, CheckerContext &Ctx, ExplodedNode *Pred = nullptr) const; + +private: + /// Perform the necessary checks and state adjustments at the end of the + /// function. + /// \p S Return statement, may be null. + ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const; }; //===----------------------------------------------------------------------===// |

