[cfe-commits] r109225 - in /cfe/trunk: lib/Checker/StreamChecker.cpp test/Analysis/stream.c
Zhongxing Xu
xuzhongxing at gmail.com
Fri Jul 23 07:14:59 PDT 2010
Author: zhongxingxu
Date: Fri Jul 23 09:14:59 2010
New Revision: 109225
URL: http://llvm.org/viewvc/llvm-project?rev=109225&view=rev
Log:
Add FILE* leak check to StreamChecker. Patch by Lei Zhang.
Modified:
cfe/trunk/lib/Checker/StreamChecker.cpp
cfe/trunk/test/Analysis/stream.c
Modified: cfe/trunk/lib/Checker/StreamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/StreamChecker.cpp?rev=109225&r1=109224&r2=109225&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/StreamChecker.cpp (original)
+++ cfe/trunk/lib/Checker/StreamChecker.cpp Fri Jul 23 09:14:59 2010
@@ -24,7 +24,7 @@
namespace {
struct StreamState {
- enum Kind { Opened, Closed, OpenFailed } K;
+ enum Kind { Opened, Closed, OpenFailed, Escaped } K;
const Stmt *S;
StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
@@ -32,6 +32,7 @@
bool isOpened() const { return K == Opened; }
bool isClosed() const { return K == Closed; }
bool isOpenFailed() const { return K == OpenFailed; }
+ bool isEscaped() const { return K == Escaped; }
bool operator==(const StreamState &X) const {
return K == X.K && S == X.S;
@@ -42,6 +43,9 @@
static StreamState getOpenFailed(const Stmt *s) {
return StreamState(OpenFailed, s);
}
+ static StreamState getEscaped(const Stmt *s) {
+ return StreamState(Escaped, s);
+ }
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
@@ -53,14 +57,15 @@
IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
- BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose;
+ BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
public:
StreamChecker()
: II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
- BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0) {}
+ BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0),
+ BT_ResourceLeak(0) {}
static void *getTag() {
static int x;
@@ -68,6 +73,9 @@
}
virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+ void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
+ void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
private:
void Fopen(CheckerContext &C, const CallExpr *CE);
@@ -386,3 +394,70 @@
// Close the File Descriptor.
return state->set<StreamState>(Sym, StreamState::getClosed(CE));
}
+
+void StreamChecker::EvalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ E = SymReaper.dead_end(); I != E; ++I) {
+ SymbolRef Sym = *I;
+ const GRState *state = C.getState();
+ const StreamState *SS = state->get<StreamState>(Sym);
+ if (!SS)
+ return;
+
+ if (SS->isOpened()) {
+ ExplodedNode *N = C.GenerateSink();
+ if (N) {
+ if (!BT_ResourceLeak)
+ BT_ResourceLeak = new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak.");
+ BugReport *R = new BugReport(*BT_ResourceLeak,
+ BT_ResourceLeak->getDescription(), N);
+ C.EmitReport(R);
+ }
+ }
+ }
+}
+
+void StreamChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {
+ SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
+ const GRState *state = B.getState();
+ typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
+ SymMap M = state->get<StreamState>();
+
+ for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ StreamState SS = I->second;
+ if (SS.isOpened()) {
+ ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ if (N) {
+ if (!BT_ResourceLeak)
+ BT_ResourceLeak = new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak.");
+ BugReport *R = new BugReport(*BT_ResourceLeak,
+ BT_ResourceLeak->getDescription(), N);
+ Eng.getBugReporter().EmitReport(R);
+ }
+ }
+ }
+}
+
+void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+ const Expr *RetE = S->getRetValue();
+ if (!RetE)
+ return;
+
+ const GRState *state = C.getState();
+ SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+
+ if (!Sym)
+ return;
+
+ const StreamState *SS = state->get<StreamState>(Sym);
+ if(!SS)
+ return;
+
+ if (SS->isOpened())
+ state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
+
+ C.addTransition(state);
+}
Modified: cfe/trunk/test/Analysis/stream.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/stream.c?rev=109225&r1=109224&r2=109225&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/stream.c (original)
+++ cfe/trunk/test/Analysis/stream.c Fri Jul 23 09:14:59 2010
@@ -17,21 +17,25 @@
FILE *p = fopen("foo", "r");
char buf[1024];
fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f2(void) {
FILE *p = fopen("foo", "r");
fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f3(void) {
FILE *p = fopen("foo", "r");
ftell(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f4(void) {
FILE *p = fopen("foo", "r");
rewind(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f5(void) {
@@ -40,6 +44,7 @@
return;
fseek(p, 1, SEEK_SET); // no-warning
fseek(p, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR.}}
+ fclose(p);
}
void f6(void) {
@@ -51,4 +56,20 @@
void f7(void) {
FILE *p = tmpfile();
ftell(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
+}
+
+void f8(int c) {
+ FILE *p = fopen("foo.c", "r");
+ if(c)
+ return; // expected-warning {{Opened File never closed. Potential Resource leak.}}
+ fclose(p);
+}
+
+FILE *f9(void) {
+ FILE *p = fopen("foo.c", "r");
+ if (p)
+ return p; // no-warning
+ else
+ return 0;
}
More information about the cfe-commits
mailing list