aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp70
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(