diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index f6abbe4f8f03..6b176b3c4e2b 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -204,7 +204,8 @@ class StreamChecker : public Checker<check::PreCall, eval::Call, BugType BT_IllegalWhence{this, "Illegal whence argument", "Stream handling error"}; BugType BT_StreamEof{this, "Stream already in EOF", "Stream handling error"}; - BugType BT_ResourceLeak{this, "Resource leak", "Stream handling error"}; + BugType BT_ResourceLeak{this, "Resource leak", "Stream handling error", + /*SuppressOnSink =*/true}; public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; @@ -337,6 +338,12 @@ private: /// to ensure uniform handling. void reportFEofWarning(CheckerContext &C, ProgramStateRef State) const; + /// Emit resource leak warnings for the given symbols. + /// Createn a non-fatal error node for these, and returns it (if any warnings + /// were generated). Return value is non-null. + ExplodedNode *reportLeaks(const SmallVector<SymbolRef, 2> &LeakedSyms, + CheckerContext &C, ExplodedNode *Pred) const; + /// Find the description data of the function called by a call event. /// Returns nullptr if no function is recognized. const FnDescription *lookupFn(const CallEvent &Call) const { @@ -956,28 +963,14 @@ void StreamChecker::reportFEofWarning(CheckerContext &C, C.addTransition(State); } -void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, - CheckerContext &C) const { - ProgramStateRef State = C.getState(); - - // TODO: Clean up the state. - const StreamMapTy &Map = State->get<StreamMap>(); - for (const auto &I : Map) { - SymbolRef Sym = I.first; - const StreamState &SS = I.second; - if (!SymReaper.isDead(Sym) || !SS.isOpened()) - continue; - - ExplodedNode *N = C.generateErrorNode(); - if (!N) - continue; - - // Do not warn for non-closed stream at program exit. - ExplodedNode *Pred = C.getPredecessor(); - if (Pred && Pred->getCFGBlock() && - Pred->getCFGBlock()->hasNoReturnElement()) - continue; +ExplodedNode * +StreamChecker::reportLeaks(const SmallVector<SymbolRef, 2> &LeakedSyms, + CheckerContext &C, ExplodedNode *Pred) const { + ExplodedNode *Err = C.generateNonFatalErrorNode(C.getState(), Pred); + if (!Err) + return Pred; + for (SymbolRef LeakSym : LeakedSyms) { // Resource leaks can result in multiple warning that describe the same kind // of programming error: // void f() { @@ -989,8 +982,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, // from a different kinds of errors), the reduction in redundant reports // makes this a worthwhile heuristic. // FIXME: Add a checker option to turn this uniqueing feature off. - - const ExplodedNode *StreamOpenNode = getAcquisitionSite(N, Sym, C); + const ExplodedNode *StreamOpenNode = getAcquisitionSite(Err, LeakSym, C); assert(StreamOpenNode && "Could not find place of stream opening."); PathDiagnosticLocation LocUsedForUniqueing = PathDiagnosticLocation::createBegin( @@ -1000,12 +992,38 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, std::unique_ptr<PathSensitiveBugReport> R = std::make_unique<PathSensitiveBugReport>( BT_ResourceLeak, - "Opened stream never closed. Potential resource leak.", N, + "Opened stream never closed. Potential resource leak.", Err, LocUsedForUniqueing, StreamOpenNode->getLocationContext()->getDecl()); - R->markInteresting(Sym); + R->markInteresting(LeakSym); C.emitReport(std::move(R)); } + + return Err; +} + +void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + llvm::SmallVector<SymbolRef, 2> LeakedSyms; + + const StreamMapTy &Map = State->get<StreamMap>(); + for (const auto &I : Map) { + SymbolRef Sym = I.first; + const StreamState &SS = I.second; + if (!SymReaper.isDead(Sym)) + continue; + if (SS.isOpened()) + LeakedSyms.push_back(Sym); + State = State->remove<StreamMap>(Sym); + } + + ExplodedNode *N = C.getPredecessor(); + if (!LeakedSyms.empty()) + N = reportLeaks(LeakedSyms, C, N); + + C.addTransition(State, N); } ProgramStateRef StreamChecker::checkPointerEscape( |