r239709 - [analyzer] Remove ObjCContainersChecker size information when a CFMutableArrayRef escapes

Devin Coughlin dcoughlin at apple.com
Sun Jun 14 18:00:42 PDT 2015


Author: dcoughlin
Date: Sun Jun 14 20:00:42 2015
New Revision: 239709

URL: http://llvm.org/viewvc/llvm-project?rev=239709&view=rev
Log:
[analyzer] Remove ObjCContainersChecker size information when a CFMutableArrayRef escapes

Update ObjCContainersChecker to be notified when pointers escape so it can
remove size information for escaping CFMutableArrayRefs. When such pointers
escape, un-analyzed code could mutate the array and cause the size information
to be incorrect.

rdar://problem/19406485

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
    cfe/trunk/test/Analysis/CFContainers.mm

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp?rev=239709&r1=239708&r2=239709&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp Sun Jun 14 20:00:42 2015
@@ -29,7 +29,8 @@ using namespace ento;
 
 namespace {
 class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
-                                             check::PostStmt<CallExpr> > {
+                                             check::PostStmt<CallExpr>,
+                                             check::PointerEscape> {
   mutable std::unique_ptr<BugType> BT;
   inline void initBugType() const {
     if (!BT)
@@ -52,6 +53,10 @@ public:
 
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+  ProgramStateRef checkPointerEscape(ProgramStateRef State,
+                                     const InvalidatedSymbols &Escaped,
+                                     const CallEvent *Call,
+                                     PointerEscapeKind Kind) const;
 };
 } // end anonymous namespace
 
@@ -146,6 +151,24 @@ void ObjCContainersChecker::checkPreStmt
   }
 }
 
+ProgramStateRef
+ObjCContainersChecker::checkPointerEscape(ProgramStateRef State,
+                                          const InvalidatedSymbols &Escaped,
+                                          const CallEvent *Call,
+                                          PointerEscapeKind Kind) const {
+  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+                                          E = Escaped.end();
+                                          I != E; ++I) {
+    SymbolRef Sym = *I;
+    // When a symbol for a mutable array escapes, we can't reason precisely
+    // about its size any more -- so remove it from the map.
+    // Note that we aren't notified here when a CFMutableArrayRef escapes as a
+    // CFArrayRef. This is because CFArrayRef is typedef'd as a pointer to a
+    // const-qualified type.
+    State = State->remove<ArraySizeMap>(Sym);
+  }
+  return State;
+}
 /// Register checker.
 void ento::registerObjCContainersChecker(CheckerManager &mgr) {
   mgr.registerChecker<ObjCContainersChecker>();

Modified: cfe/trunk/test/Analysis/CFContainers.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/CFContainers.mm?rev=239709&r1=239708&r2=239709&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/CFContainers.mm (original)
+++ cfe/trunk/test/Analysis/CFContainers.mm Sun Jun 14 20:00:42 2015
@@ -19,6 +19,7 @@ typedef struct {
 } CFArrayCallBacks;
 typedef const struct __CFArray * CFArrayRef;
 CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
+typedef struct __CFArray * CFMutableArrayRef;
 typedef const struct __CFString * CFStringRef;
 enum {
     kCFNumberSInt8Type = 1,
@@ -202,3 +203,24 @@ void TestConst(CFArrayRef A, CFIndex sIn
 void TestNullArray() {
   CFArrayGetValueAtIndex(0, 0);
 }
+
+void ArrayRefMutableEscape(CFMutableArrayRef a);
+void ArrayRefEscape(CFArrayRef a);
+
+void TestCFMutableArrayRefEscapeViaMutableArgument(CFMutableArrayRef a) {
+  CFIndex aLen = CFArrayGetCount(a);
+  ArrayRefMutableEscape(a);
+
+  // ArrayRefMutableEscape could mutate a to make it have
+  // at least aLen + 1 elements, so do not report an error here.
+  CFArrayGetValueAtIndex(a, aLen);
+}
+
+void TestCFMutableArrayRefEscapeViaImmutableArgument(CFMutableArrayRef a) {
+  CFIndex aLen = CFArrayGetCount(a);
+  ArrayRefEscape(a);
+
+  // ArrayRefEscape is declared to take a CFArrayRef (i.e, an immutable array)
+  // so we assume it does not change the length of a.
+  CFArrayGetValueAtIndex(a, aLen); // expected-warning {{Index is out of bounds}}
+}





More information about the cfe-commits mailing list