]> granicus.if.org Git - clang/commitdiff
[analyzer] Assume pointer escapes when a callback is passed inside
authorAnna Zaks <ganna@apple.com>
Thu, 3 May 2012 23:50:33 +0000 (23:50 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 3 May 2012 23:50:33 +0000 (23:50 +0000)
a struct.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156135 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/ObjCMessage.cpp
test/Analysis/malloc.c
test/Analysis/system-header-simulator.h

index dc24e818ffa92ba4fccfbd0e3ddc5768bfdd0afa..0c6d8a8b63dc95eb0ca1c0854a9bc11a295e48de 100644 (file)
@@ -89,10 +89,28 @@ const Decl *CallOrObjCMessage::getDecl() const {
 }
 
 bool CallOrObjCMessage::isCallbackArg(unsigned Idx, const Type *T) const {
-  // Should we dig into struct fields, arrays ect?
+  // If the parameter is 0, it's harmless.
+  if (getArgSVal(Idx).isZeroConstant())
+    return false;
+    
+  // If a parameter is a block or a callback, assume it can modify pointer.
   if (T->isBlockPointerType() || T->isFunctionPointerType())
-    if (!getArgSVal(Idx).isZeroConstant())
-      return true;
+    return true;
+
+  // Check if a callback is passed inside a struct (for both, struct passed by
+  // reference and by value). Dig just one level into the struct for now.
+  if (const PointerType *PT = dyn_cast<PointerType>(T))
+    T = PT->getPointeeType().getTypePtr();
+
+  if (const RecordType *RT = T->getAsStructureType()) {
+    const RecordDecl *RD = RT->getDecl();
+    for (RecordDecl::field_iterator I = RD->field_begin(),
+                                    E = RD->field_end(); I != E; ++I ) {
+      const Type *FieldT = I->getType().getTypePtr();
+      if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
+        return true;
+    }
+  }
   return false;
 }
 
index f5bff4fa43b1326fa8bc1f5951e967cf85f56821..a7d5b0b0e941cb679d243633532ae8c90cb4782a 100644 (file)
@@ -819,6 +819,16 @@ void r11160612_4() {
   sqlite3_bind_text_my(0, x, 12, free); // no - warning
 }
 
+// Passing callbacks in a struct.
+void r11160612_5(StWithCallback St) {
+  void *x = malloc(12);
+  dealocateMemWhenDoneByVal(x, St);
+}
+void r11160612_6(StWithCallback St) {
+  void *x = malloc(12);
+  dealocateMemWhenDoneByRef(&St, x);
+}
+
 // ----------------------------------------------------------------------------
 // Below are the known false positives.
 
index c910ad9694c44b7bdbc0f396d3b691fcfc7cbacf..a8cba9ce5b252cb9e5905a1f8d5b6f6f6f254549 100644 (file)
@@ -37,3 +37,12 @@ FILE *funopen(const void *,
                  int (*)(void *));
 
 int sqlite3_bind_text_my(int, const char*, int n, void(*)(void*));
+
+typedef void (*freeCallback) (void*);
+typedef struct {
+  int i;
+  freeCallback fc;
+} StWithCallback;
+
+int dealocateMemWhenDoneByVal(void*, StWithCallback);
+int dealocateMemWhenDoneByRef(StWithCallback*, const void*);