22 #include "llvm/ADT/ImmutableMap.h"
24 using namespace clang;
30 enum Kind { Opened, Closed, OpenFailed, Escaped } K;
33 StreamState(
Kind k,
const Stmt *s) : K(k),
S(s) {}
35 bool isOpened()
const {
return K == Opened; }
36 bool isClosed()
const {
return K == Closed; }
41 return K == X.K &&
S == X.S;
44 static StreamState getOpened(
const Stmt *s) {
return StreamState(Opened, s); }
45 static StreamState getClosed(
const Stmt *s) {
return StreamState(Closed, s); }
46 static StreamState getOpenFailed(
const Stmt *s) {
47 return StreamState(OpenFailed, s);
49 static StreamState getEscaped(
const Stmt *s) {
50 return StreamState(Escaped, s);
53 void Profile(llvm::FoldingSetNodeID &
ID)
const {
59 class StreamChecker :
public Checker<eval::Call,
60 check::DeadSymbols > {
61 mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
63 *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
64 *II_clearerr, *II_feof, *II_ferror, *II_fileno;
65 mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
66 BT_doubleclose, BT_ResourceLeak;
70 : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
71 II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
72 II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
73 II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr),
74 II_ferror(nullptr), II_fileno(nullptr) {}
110 if (!FD || FD->
getKind() != Decl::Function)
135 II_clearerr = &Ctx.
Idents.
get(
"clearerr");
217 .castAs<DefinedSVal>();
224 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, RetVal);
229 stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
231 stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
260 if (!(state = CheckNullStream(state->getSVal(CE->
getArg(0),
270 int64_t x = CI->getValue().getSExtValue();
271 if (x >= 0 && x <= 2)
275 if (!BT_illegalwhence)
276 BT_illegalwhence.reset(
277 new BuiltinBug(
this,
"Illegal whence argument",
278 "The whence argument to fseek() should be "
279 "SEEK_SET, SEEK_END, or SEEK_CUR."));
281 *BT_illegalwhence, BT_illegalwhence->getDescription(), N));
349 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, *DV);
351 if (!stateNotNull && stateNull) {
354 BT_nullfp.reset(
new BuiltinBug(
this,
"NULL stream pointer",
355 "Stream pointer might be NULL."));
357 *BT_nullfp, BT_nullfp->getDescription(), N));
372 const StreamState *SS = state->get<StreamMap>(Sym);
380 if (SS->isClosed()) {
385 this,
"Double fclose",
"Try to close a file Descriptor already"
386 " closed. Cause undefined behaviour."));
388 *BT_doubleclose, BT_doubleclose->getDescription(), N));
394 return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
397 void StreamChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
401 E = SymReaper.
dead_end(); I != E; ++I) {
404 const StreamState *SS = state->get<StreamMap>(Sym);
408 if (SS->isOpened()) {
411 if (!BT_ResourceLeak)
413 this,
"Resource Leak",
414 "Opened File never closed. Potential Resource leak."));
416 *BT_ResourceLeak, BT_ResourceLeak->getDescription(), N));
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
bool operator==(CanQual< T > x, CanQual< U > y)
IdentifierInfo * getIdentifier() const
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
Value representing integer constant.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
Symbolic value. These values used to capture symbolic execution of the program.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
unsigned blockCount() const
Returns the number of times the current block has been visited along the analyzed path...
dead_iterator dead_begin() const
const LocationContext * getLocationContext() const
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
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.
ID
Defines the set of possible language-specific address spaces.
const ProgramStateRef & getState() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
SymbolSetTy::const_iterator dead_iterator
ConstraintManager & getConstraintManager()
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
dead_iterator dead_end() const
A class responsible for cleaning up unused symbols.
REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, SymbolRef, MacOSKeychainAPIChecker::AllocationState) static bool isEnclosingFunctionParam(const Expr *E)
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef. Otherwise, return 0.
SValBuilder & getSValBuilder()
const LocationContext * getLocationContext() const