@@ -337,6 +337,12 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
337
337
// / to ensure uniform handling.
338
338
void reportFEofWarning (CheckerContext &C, ProgramStateRef State) const ;
339
339
340
+ // / Emit resource leak warnings for the given symbols.
341
+ // / Createn a non-fatal error node for these, and returns it (if any warnings
342
+ // / were generated). Return value is non-null.
343
+ ExplodedNode *reportLeaks (const SmallVector<SymbolRef, 2 > &LeakedSyms,
344
+ CheckerContext &C, ExplodedNode *Pred) const ;
345
+
340
346
// / Find the description data of the function called by a call event.
341
347
// / Returns nullptr if no function is recognized.
342
348
const FnDescription *lookupFn (const CallEvent &Call) const {
@@ -956,28 +962,19 @@ void StreamChecker::reportFEofWarning(CheckerContext &C,
956
962
C.addTransition (State);
957
963
}
958
964
959
- void StreamChecker::checkDeadSymbols (SymbolReaper &SymReaper,
960
- CheckerContext &C) const {
961
- ProgramStateRef State = C.getState ();
962
-
963
- // TODO: Clean up the state.
964
- const StreamMapTy &Map = State->get <StreamMap>();
965
- for (const auto &I : Map) {
966
- SymbolRef Sym = I.first ;
967
- const StreamState &SS = I.second ;
968
- if (!SymReaper.isDead (Sym) || !SS.isOpened ())
969
- continue ;
970
-
971
- ExplodedNode *N = C.generateErrorNode ();
972
- if (!N)
973
- continue ;
965
+ ExplodedNode *
966
+ StreamChecker::reportLeaks (const SmallVector<SymbolRef, 2 > &LeakedSyms,
967
+ CheckerContext &C, ExplodedNode *Pred) const {
968
+ // Do not warn for non-closed stream at program exit.
969
+ // FIXME: Use BugType::SuppressOnSink instead.
970
+ if (Pred && Pred->getCFGBlock () && Pred->getCFGBlock ()->hasNoReturnElement ())
971
+ return Pred;
974
972
975
- // Do not warn for non-closed stream at program exit.
976
- ExplodedNode *Pred = C.getPredecessor ();
977
- if (Pred && Pred->getCFGBlock () &&
978
- Pred->getCFGBlock ()->hasNoReturnElement ())
979
- continue ;
973
+ ExplodedNode *Err = C.generateNonFatalErrorNode (C.getState (), Pred);
974
+ if (!Err)
975
+ return Pred;
980
976
977
+ for (SymbolRef LeakSym : LeakedSyms) {
981
978
// Resource leaks can result in multiple warning that describe the same kind
982
979
// of programming error:
983
980
// void f() {
@@ -989,8 +986,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
989
986
// from a different kinds of errors), the reduction in redundant reports
990
987
// makes this a worthwhile heuristic.
991
988
// FIXME: Add a checker option to turn this uniqueing feature off.
992
-
993
- const ExplodedNode *StreamOpenNode = getAcquisitionSite (N, Sym, C);
989
+ const ExplodedNode *StreamOpenNode = getAcquisitionSite (Err, LeakSym, C);
994
990
assert (StreamOpenNode && " Could not find place of stream opening." );
995
991
PathDiagnosticLocation LocUsedForUniqueing =
996
992
PathDiagnosticLocation::createBegin (
@@ -1000,12 +996,38 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1000
996
std::unique_ptr<PathSensitiveBugReport> R =
1001
997
std::make_unique<PathSensitiveBugReport>(
1002
998
BT_ResourceLeak,
1003
- " Opened stream never closed. Potential resource leak." , N ,
999
+ " Opened stream never closed. Potential resource leak." , Err ,
1004
1000
LocUsedForUniqueing,
1005
1001
StreamOpenNode->getLocationContext ()->getDecl ());
1006
- R->markInteresting (Sym );
1002
+ R->markInteresting (LeakSym );
1007
1003
C.emitReport (std::move (R));
1008
1004
}
1005
+
1006
+ return Err;
1007
+ }
1008
+
1009
+ void StreamChecker::checkDeadSymbols (SymbolReaper &SymReaper,
1010
+ CheckerContext &C) const {
1011
+ ProgramStateRef State = C.getState ();
1012
+
1013
+ llvm::SmallVector<SymbolRef, 2 > LeakedSyms;
1014
+
1015
+ const StreamMapTy &Map = State->get <StreamMap>();
1016
+ for (const auto &I : Map) {
1017
+ SymbolRef Sym = I.first ;
1018
+ const StreamState &SS = I.second ;
1019
+ if (!SymReaper.isDead (Sym))
1020
+ continue ;
1021
+ if (SS.isOpened ())
1022
+ LeakedSyms.push_back (Sym);
1023
+ State = State->remove <StreamMap>(Sym);
1024
+ }
1025
+
1026
+ ExplodedNode *N = C.getPredecessor ();
1027
+ if (!LeakedSyms.empty ())
1028
+ N = reportLeaks (LeakedSyms, C, N);
1029
+
1030
+ C.addTransition (State, N);
1009
1031
}
1010
1032
1011
1033
ProgramStateRef StreamChecker::checkPointerEscape (
0 commit comments