]> granicus.if.org Git - clang/commitdiff
Add use-after-free check to MallocChecker.
authorZhongxing Xu <xuzhongxing@gmail.com>
Wed, 10 Mar 2010 04:58:55 +0000 (04:58 +0000)
committerZhongxing Xu <xuzhongxing@gmail.com>
Wed, 10 Mar 2010 04:58:55 +0000 (04:58 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98136 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Checker/PathSensitive/SVals.h
lib/Checker/MallocChecker.cpp
lib/Checker/SVals.cpp
test/Analysis/malloc.c

index 65a8a2c01df552aab48c762e4765a31d6f4d3bec..040db831b8c0f9a221063a4441bca97d8c2f848a 100644 (file)
@@ -112,6 +112,9 @@ public:
   ///  wraps a symbol, return that SymbolRef.  Otherwise return a SymbolData*
   SymbolRef getAsLocSymbol() const;
 
+  /// Get the symbol in the SVal or its base region.
+  SymbolRef getLocSymbolInBase() const;
+
   /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
   ///  Otherwise return a SymbolRef where 'isValid()' returns false.
   SymbolRef getAsSymbol() const;
index 4ff98642e1c278a529489c08b97ff59b30dc7a60..a08afc4b795921ddb55bf78c64e9134c450ca0d4 100644 (file)
@@ -57,17 +57,20 @@ class RegionState {};
 class MallocChecker : public CheckerVisitor<MallocChecker> {
   BuiltinBug *BT_DoubleFree;
   BuiltinBug *BT_Leak;
+  BuiltinBug *BT_UseFree;
   IdentifierInfo *II_malloc, *II_free, *II_realloc;
 
 public:
   MallocChecker() 
-    : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {}
+    : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), 
+      II_malloc(0), II_free(0), II_realloc(0) {}
   static void *getTag();
   bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
   void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
   void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
   void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
   const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption);
+  void VisitLocation(CheckerContext &C, const Stmt *S, SVal l);
 
 private:
   void MallocMem(CheckerContext &C, const CallExpr *CE);
@@ -339,3 +342,22 @@ const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond,
 
   return state;
 }
+
+// Check if the location is a freed symbolic region.
+void MallocChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) {
+  SymbolRef Sym = l.getLocSymbolInBase();
+  if (Sym) {
+    const RefState *RS = C.getState()->get<RegionState>(Sym);
+    if (RS)
+      if (RS->isReleased()) {
+        ExplodedNode *N = C.GenerateSink();
+        if (!BT_UseFree)
+          BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
+                                      " it is freed.");
+
+        BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
+                                     N);
+        C.EmitReport(R);
+      }
+  }
+}
index 28b3fce050bb8fe7dbfbf513b951da7fa0a49936..4bfa2cdafb460ec20911973741de463ec04f808a 100644 (file)
@@ -70,6 +70,25 @@ SymbolRef SVal::getAsLocSymbol() const {
   return NULL;
 }
 
+/// Get the symbol in the SVal or its base region.
+SymbolRef SVal::getLocSymbolInBase() const {
+  const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);
+
+  if (!X)
+    return 0;
+
+  const MemRegion *R = X->getRegion();
+
+  while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
+      return SymR->getSymbol();
+    else
+      R = SR->getSuperRegion();
+  }
+
+  return 0;
+}
+
 /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
 ///  Otherwise return 0.
 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
index 3cce1b0d2ef4c5be3097b3a30bf873c09e2d7de4..21b6d46a245e676ba2bf28fbda35800a42f23aee 100644 (file)
@@ -61,3 +61,9 @@ void pr6069() {
 void pr6293() {
   free(0);
 }
+
+void f7() {
+  char *x = (char*) malloc(4);
+  free(x);
+  x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+}