diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 77 |
1 files changed, 38 insertions, 39 deletions
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index e47494a3e90b3..2c1e139330d68 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -555,7 +555,7 @@ public: } const RetainSummary *find(IdentifierInfo* II, Selector S) { - // FIXME: Class method lookup. Right now we dont' have a good way + // FIXME: Class method lookup. Right now we don't have a good way // of going between IdentifierInfo* and the class hierarchy. MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); @@ -883,21 +883,22 @@ RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) { //===----------------------------------------------------------------------===// static bool isRetain(const FunctionDecl *FD, StringRef FName) { - return FName.endswith("Retain"); + return FName.startswith_lower("retain") || FName.endswith_lower("retain"); } static bool isRelease(const FunctionDecl *FD, StringRef FName) { - return FName.endswith("Release"); + return FName.startswith_lower("release") || FName.endswith_lower("release"); } static bool isAutorelease(const FunctionDecl *FD, StringRef FName) { - return FName.endswith("Autorelease"); + return FName.startswith_lower("autorelease") || + FName.endswith_lower("autorelease"); } static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) { // FIXME: Remove FunctionDecl parameter. // FIXME: Is it really okay if MakeCollectable isn't a suffix? - return FName.find("MakeCollectable") != StringRef::npos; + return FName.find_lower("MakeCollectable") != StringRef::npos; } static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { @@ -1787,8 +1788,7 @@ namespace { //===---------===// // Bug Reports. // //===---------===// - - class CFRefReportVisitor : public BugReporterVisitorImpl<CFRefReportVisitor> { + class CFRefReportVisitor : public BugReporterVisitor { protected: SymbolRef Sym; const SummaryLogTy &SummaryLog; @@ -1809,7 +1809,7 @@ namespace { BugReporterContext &BRC, BugReport &BR) override; - std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, + std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) override; }; @@ -1820,18 +1820,9 @@ namespace { const SummaryLogTy &log) : CFRefReportVisitor(sym, GCEnabled, log) {} - std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, + std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) override; - - std::unique_ptr<BugReporterVisitor> clone() const override { - // The curiously-recurring template pattern only works for one level of - // subclassing. Rather than make a new template base for - // CFRefReportVisitor, we simply override clone() to do the right thing. - // This could be trouble someday if BugReporterVisitorImpl is ever - // used for something else besides a convenient implementation of clone(). - return llvm::make_unique<CFRefLeakReportVisitor>(*this); - } }; class CFRefReport : public BugReport { @@ -1929,6 +1920,14 @@ static bool isNumericLiteralExpression(const Expr *E) { isa<CXXBoolLiteralExpr>(E); } +static Optional<std::string> describeRegion(const MemRegion *MR) { + if (const auto *VR = dyn_cast_or_null<VarRegion>(MR)) + return std::string(VR->getDecl()->getName()); + // Once we support more storage locations for bindings, + // this would need to be improved. + return None; +} + /// Returns true if this stack frame is for an Objective-C method that is a /// property getter or setter whose body has been synthesized by the analyzer. static bool isSynthesizedAccessor(const StackFrameContext *SFC) { @@ -1969,8 +1968,8 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); if (isa<ObjCIvarRefExpr>(S) && - isSynthesizedAccessor(LCtx->getCurrentStackFrame())) { - S = LCtx->getCurrentStackFrame()->getCallSite(); + isSynthesizedAccessor(LCtx->getStackFrame())) { + S = LCtx->getStackFrame()->getCallSite(); } if (isa<ObjCArrayLiteral>(S)) { @@ -2298,7 +2297,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>(); // Do not show local variables belonging to a function other than // where the error is reported. - if (!VR || VR->getStackFrame() == LeakContext->getCurrentStackFrame()) + if (!VR || VR->getStackFrame() == LeakContext->getStackFrame()) FirstBinding = R; } @@ -2356,14 +2355,14 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, InterestingMethodContext); } -std::unique_ptr<PathDiagnosticPiece> +std::shared_ptr<PathDiagnosticPiece> CFRefReportVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndN, BugReport &BR) { BR.markInteresting(Sym); return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); } -std::unique_ptr<PathDiagnosticPiece> +std::shared_ptr<PathDiagnosticPiece> CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndN, BugReport &BR) { @@ -2393,9 +2392,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, os << "Object leaked: "; - if (FirstBinding) { - os << "object allocated and stored into '" - << FirstBinding->getString() << '\''; + Optional<std::string> RegionDescription = describeRegion(FirstBinding); + if (RegionDescription) { + os << "object allocated and stored into '" << *RegionDescription << '\''; } else os << "allocated object"; @@ -2450,7 +2449,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, os << " is not referenced later in this execution path and has a retain " "count of +" << RV->getCount(); - return llvm::make_unique<PathDiagnosticEventPiece>(L, os.str()); + return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); } void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) { @@ -2513,7 +2512,8 @@ void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,SymbolRef sym) { UniqueingDecl = AllocNode->getLocationContext()->getDecl(); } -void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine) { +void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled, + bool IncludeAllocationLine) { assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid()); Description.clear(); llvm::raw_string_ostream os(Description); @@ -2522,8 +2522,9 @@ void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled, boo os << "(when using garbage collection) "; os << "of an object"; - if (AllocBinding) { - os << " stored into '" << AllocBinding->getString() << '\''; + Optional<std::string> RegionDescription = describeRegion(AllocBinding); + if (RegionDescription) { + os << " stored into '" << *RegionDescription << '\''; if (IncludeAllocationLine) { FullSourceLoc SL(AllocStmt->getLocStart(), Ctx.getSourceManager()); os << " (allocated on line " << SL.getSpellingLineNumber() << ")"; @@ -2742,7 +2743,7 @@ public: void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkBeginFunction(CheckerContext &C) const; - void checkEndFunction(CheckerContext &C) const; + void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind &hasErr, @@ -2799,9 +2800,7 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE, return; ProgramStateRef state = C.getState(); - const BlockDataRegion *R = - cast<BlockDataRegion>(state->getSVal(BE, - C.getLocationContext()).getAsRegion()); + auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion()); BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), E = R->referenced_vars_end(); @@ -2851,7 +2850,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE, } ProgramStateRef state = C.getState(); - SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol(); + SymbolRef Sym = C.getSVal(CE).getAsLocSymbol(); if (!Sym) return; const RefVal* T = getRefBinding(state, Sym); @@ -2874,7 +2873,7 @@ void RetainCountChecker::processObjCLiterals(CheckerContext &C, ProgramStateRef state = C.getState(); const ExplodedNode *pred = C.getPredecessor(); for (const Stmt *Child : Ex->children()) { - SVal V = state->getSVal(Child, pred->getLocationContext()); + SVal V = pred->getSVal(Child); if (SymbolRef sym = V.getAsSymbol()) if (const RefVal* T = getRefBinding(state, sym)) { RefVal::Kind hasErr = (RefVal::Kind) 0; @@ -2913,10 +2912,9 @@ void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, CheckerContext &C) const { const ExplodedNode *Pred = C.getPredecessor(); - const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); - if (SymbolRef Sym = State->getSVal(Ex, LCtx).getAsSymbol()) { + if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) { QualType ResultTy = Ex->getType(); State = setRefBinding(State, Sym, RefVal::makeNotOwned(RetEffect::ObjC, ResultTy)); @@ -3993,7 +3991,8 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { Ctx.addTransition(state); } -void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { +void RetainCountChecker::checkEndFunction(const ReturnStmt *RS, + CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); RefBindingsTy B = state->get<RefBindings>(); ExplodedNode *Pred = Ctx.getPredecessor(); |