34 StreamState(Kind InK) : K(InK) { }
37 bool isOpened()
const {
return K == Opened; }
38 bool isClosed()
const {
return K ==
Closed; }
40 static StreamState getOpened() {
return StreamState(Opened); }
41 static StreamState getClosed() {
return StreamState(Closed); }
46 void Profile(llvm::FoldingSetNodeID &ID)
const {
51class SimpleStreamChecker :
public Checker<check::PostCall,
54 check::PointerEscape> {
57 std::unique_ptr<BugType> DoubleCloseBugType;
58 std::unique_ptr<BugType> LeakBugType;
60 void reportDoubleClose(
SymbolRef FileDescSym,
67 bool guaranteedNotToCloseFile(
const CallEvent &Call)
const;
70 SimpleStreamChecker();
92SimpleStreamChecker::SimpleStreamChecker()
93 : OpenFn({
"fopen"}), CloseFn({
"fclose"}, 1) {
95 DoubleCloseBugType.reset(
96 new BugType(
this,
"Double fclose",
"Unix Stream API Error"));
100 new BugType(
this,
"Resource Leak",
"Unix Stream API Error",
104void SimpleStreamChecker::checkPostCall(
const CallEvent &Call,
106 if (!
Call.isGlobalCFunction())
109 if (!OpenFn.matches(Call))
119 State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
120 C.addTransition(State);
123void SimpleStreamChecker::checkPreCall(
const CallEvent &Call,
125 if (!
Call.isGlobalCFunction())
128 if (!CloseFn.matches(Call))
138 const StreamState *SS = State->get<StreamMap>(FileDesc);
139 if (SS && SS->isClosed()) {
140 reportDoubleClose(FileDesc, Call,
C);
145 State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
146 C.addTransition(State);
151 if (IsSymDead && SS.isOpened()) {
161void SimpleStreamChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
164 SymbolVector LeakedStreams;
165 StreamMapTy TrackedStreams = State->get<StreamMap>();
166 for (StreamMapTy::iterator I = TrackedStreams.begin(),
167 E = TrackedStreams.end(); I != E; ++I) {
169 bool IsSymDead = SymReaper.
isDead(Sym);
172 if (
isLeaked(Sym, I->second, IsSymDead, State))
173 LeakedStreams.push_back(Sym);
177 State = State->remove<StreamMap>(Sym);
183 reportLeaks(LeakedStreams,
C, N);
186void SimpleStreamChecker::reportDoubleClose(
SymbolRef FileDescSym,
196 auto R = std::make_unique<PathSensitiveBugReport>(
197 *DoubleCloseBugType,
"Closing a previously closed file stream", ErrNode);
198 R->addRange(
Call.getSourceRange());
199 R->markInteresting(FileDescSym);
200 C.emitReport(std::move(R));
208 for (
SymbolRef LeakedStream : LeakedStreams) {
209 auto R = std::make_unique<PathSensitiveBugReport>(
210 *LeakBugType,
"Opened file is never closed; potential resource leak",
212 R->markInteresting(LeakedStream);
213 C.emitReport(std::move(R));
217bool SimpleStreamChecker::guaranteedNotToCloseFile(
const CallEvent &Call)
const{
219 if (!
Call.isInSystemHeader())
223 if (
Call.argumentsMayEscape())
244 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
251 State = State->remove<StreamMap>(Sym);
261bool ento::shouldRegisterSimpleStreamChecker(
const CheckerManager &mgr) {
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static bool isLeaked(SymbolRef Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State)
This class represents a description of a function call using the number of arguments and the name of ...
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ C
Languages that the frontend can parse and compile.