]> granicus.if.org Git - clang/commitdiff
[analyzer] Malloc: drop symbols captured by blocks.
authorAnna Zaks <ganna@apple.com>
Thu, 22 Mar 2012 00:57:20 +0000 (00:57 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 22 Mar 2012 00:57:20 +0000 (00:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153232 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
test/Analysis/malloc.mm

index 65a6aacc67e1a1a1c34fbeccccfabca5f44bd017..502fb1ed7569e43e7bb8612fbd114a1e661013a9 100644 (file)
@@ -89,6 +89,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
                                      check::PreStmt<ReturnStmt>,
                                      check::PreStmt<CallExpr>,
                                      check::PostStmt<CallExpr>,
+                                     check::PostStmt<BlockExpr>,
                                      check::Location,
                                      check::Bind,
                                      eval::Assume,
@@ -116,6 +117,7 @@ public:
 
   void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
   void checkEndPath(CheckerContext &C) const;
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@@ -1008,6 +1010,46 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
     checkEscape(Sym, E, C);
 }
 
+// TODO: Blocks should be either inlined or should call invalidate regions
+// upon invocation. After that's in place, special casing here will not be 
+// needed.
+void MallocChecker::checkPostStmt(const BlockExpr *BE,
+                                  CheckerContext &C) const {
+
+  // Scan the BlockDecRefExprs for any object the retain count checker
+  // may be tracking.
+  if (!BE->getBlockDecl()->hasCaptures())
+    return;
+
+  ProgramStateRef state = C.getState();
+  const BlockDataRegion *R =
+    cast<BlockDataRegion>(state->getSVal(BE,
+                                         C.getLocationContext()).getAsRegion());
+
+  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+                                            E = R->referenced_vars_end();
+
+  if (I == E)
+    return;
+
+  SmallVector<const MemRegion*, 10> Regions;
+  const LocationContext *LC = C.getLocationContext();
+  MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
+
+  for ( ; I != E; ++I) {
+    const VarRegion *VR = *I;
+    if (VR->getSuperRegion() == R) {
+      VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+    }
+    Regions.push_back(VR);
+  }
+
+  state =
+    state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+                                    Regions.data() + Regions.size()).getState();
+  C.addTransition(state);
+}
+
 bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
                                       const Stmt *S) const {
   assert(Sym);
index 31db5ced15a1023dfbb185e84577cef057fb4d3e..4cb2cfa328a9ca6e74763c6261bee08f1d4dbd87 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
 #include "system-header-simulator-objc.h"
 
 typedef __typeof(sizeof(int)) size_t;
@@ -97,3 +97,12 @@ NSData *radar10976702() {
   return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning
 }
 
+void testBlocks() {
+  int *x= (int*)malloc(sizeof(int));
+  int (^myBlock)(int) = ^(int num) {
+    free(x);
+    return num;
+  };
+  myBlock(3);
+}
+