[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