24 using namespace clang;
32 enum Kind { Opened, Closed } K;
33 StreamState(
Kind InK) : K(InK) { }
36 bool isOpened()
const {
return K == Opened; }
37 bool isClosed()
const {
return K == Closed; }
39 static StreamState getOpened() {
return StreamState(Opened); }
40 static StreamState getClosed() {
return StreamState(Closed); }
45 void Profile(llvm::FoldingSetNodeID &
ID)
const {
50 class SimpleStreamChecker :
public Checker<check::PostCall,
53 check::PointerEscape> {
57 std::unique_ptr<BugType> DoubleCloseBugType;
58 std::unique_ptr<BugType> LeakBugType;
60 void initIdentifierInfo(
ASTContext &Ctx)
const;
62 void reportDoubleClose(
SymbolRef FileDescSym,
69 bool guaranteedNotToCloseFile(
const CallEvent &Call)
const;
72 SimpleStreamChecker();
101 bool VisitSymbol(
SymbolRef sym)
override {
102 state = state->remove<StreamMap>(sym);
108 SimpleStreamChecker::SimpleStreamChecker()
109 : IIfopen(nullptr), IIfclose(nullptr) {
111 DoubleCloseBugType.reset(
112 new BugType(
this,
"Double fclose",
"Unix Stream API Error"));
115 new BugType(
this,
"Resource Leak",
"Unix Stream API Error"));
117 LeakBugType->setSuppressOnSink(
true);
120 void SimpleStreamChecker::checkPostCall(
const CallEvent &Call,
137 State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
141 void SimpleStreamChecker::checkPreCall(
const CallEvent &Call,
161 const StreamState *SS = State->get<StreamMap>(FileDesc);
162 if (SS && SS->isClosed()) {
163 reportDoubleClose(FileDesc, Call, C);
168 State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
174 if (IsSymDead && SS.isOpened()) {
184 void SimpleStreamChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
187 SymbolVector LeakedStreams;
188 StreamMapTy TrackedStreams = State->get<StreamMap>();
189 for (StreamMapTy::iterator I = TrackedStreams.begin(),
190 E = TrackedStreams.end(); I != E; ++I) {
192 bool IsSymDead = SymReaper.
isDead(Sym);
195 if (
isLeaked(Sym, I->second, IsSymDead, State))
196 LeakedStreams.push_back(Sym);
200 State = State->remove<StreamMap>(Sym);
204 reportLeaks(LeakedStreams, C, N);
207 void SimpleStreamChecker::reportDoubleClose(
SymbolRef FileDescSym,
217 auto R = llvm::make_unique<BugReport>(*DoubleCloseBugType,
218 "Closing a previously closed file stream", ErrNode);
220 R->markInteresting(FileDescSym);
229 for (
SymbolRef LeakedStream : LeakedStreams) {
230 auto R = llvm::make_unique<BugReport>(*LeakBugType,
231 "Opened file is never closed; potential resource leak", ErrNode);
232 R->markInteresting(LeakedStream);
237 bool SimpleStreamChecker::guaranteedNotToCloseFile(
const CallEvent &Call)
const{
264 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
271 State = State->remove<StreamMap>(Sym);
276 void SimpleStreamChecker::initIdentifierInfo(
ASTContext &Ctx)
const {
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
bool isInSystemHeader() const
Returns true if the callee is known to be from a system header.
bool operator==(CanQual< T > x, CanQual< U > y)
virtual bool argumentsMayEscape() const
Returns true if any of the arguments are known to escape to long- term storage, even if this method w...
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
Symbolic value. These values used to capture symbolic execution of the program.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static bool isLeaked(SymbolRef Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State)
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
bool isGlobalCFunction(StringRef SpecificName=StringRef()) const
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
ID
Defines the set of possible language-specific address spaces.
bool isDead(SymbolRef sym) const
Returns whether or not a symbol has been confirmed dead.
const ProgramStateRef & getState() const
The pointer has been passed to a function call directly.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
A class responsible for cleaning up unused symbols.
virtual SourceRange getSourceRange() const
Returns a source range for the entire call, suitable for outputting in diagnostics.
REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, SymbolRef, MacOSKeychainAPIChecker::AllocationState) static bool isEnclosingFunctionParam(const Expr *E)
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
ASTContext & getASTContext()
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
Represents an abstract call to a function or method along a particular path.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef. Otherwise, return 0.
SVal getReturnValue() const
Returns the return value of the call.