]> granicus.if.org Git - clang/commitdiff
Malloc checker basically works now.
authorZhongxing Xu <xuzhongxing@gmail.com>
Fri, 13 Nov 2009 07:48:11 +0000 (07:48 +0000)
committerZhongxing Xu <xuzhongxing@gmail.com>
Fri, 13 Nov 2009 07:48:11 +0000 (07:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@87094 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/MallocChecker.cpp
test/Analysis/malloc.c [new file with mode: 0644]

index f007aa65da1b1dd1be933837a731d36e647bd85c..6655194d5e9285b8de5ed40899acae0547ab21d2 100644 (file)
@@ -30,11 +30,12 @@ class VISIBILITY_HIDDEN RegionState {};
 
 class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
   BuiltinBug *BT_DoubleFree;
+  BuiltinBug *BT_Leak;
   IdentifierInfo *II_malloc;
   IdentifierInfo *II_free;
 
 public:
-  MallocChecker() : BT_DoubleFree(0) {}
+  MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
   static void *getTag();
   void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
   void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
@@ -81,7 +82,7 @@ void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
   if (!II_malloc)
     II_malloc = &Ctx.Idents.get("malloc");
   if (!II_free)
-    II_malloc = &Ctx.Idents.get("free");
+    II_free = &Ctx.Idents.get("free");
 
   if (FD->getIdentifier() == II_malloc) {
     MallocMem(C, CE);
@@ -135,4 +136,25 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
 
 void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
                                     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 RefState *RS = state->get<RegionState>(Sym);
+    if (!RS)
+      return;
+
+    if (*RS == Allocated) {
+      ExplodedNode *N = C.GenerateNode(S, true);
+      if (N) {
+        if (!BT_Leak)
+          BT_Leak = new BuiltinBug("Memory leak",
+                     "Allocated memory never released. Potential memory leak.");
+        // FIXME: where it is allocated.
+        BugReport *R = new BugReport(*BT_Leak,
+                                     BT_Leak->getDescription().c_str(), N);
+        C.EmitReport(R);
+      }
+    }
+  }
 }
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
new file mode 100644 (file)
index 0000000..270b3d1
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-experimental-checks -analyzer-store=region -verify %s
+#include <stdlib.h>
+
+void f1() {
+  int *p = malloc(10);
+  return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+}
+
+void f2() {
+  int *p = malloc(10);
+  free(p);
+  free(p); // expected-warning{{Try to free a memory block that has been released}}
+}