r289047 - [analyzer] Add dispatch_data_create as a special case in RetainCountChecker.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 8 06:05:48 PST 2016


Author: dergachev
Date: Thu Dec  8 08:05:48 2016
New Revision: 289047

URL: http://llvm.org/viewvc/llvm-project?rev=289047&view=rev
Log:
[analyzer] Add dispatch_data_create as a special case in RetainCountChecker.

This function receives a callback block. The analyzer suspects that this block
may be used to take care of releasing the libdispatch object returned from
the function. In fact, it doesn't - it only releases the raw data buffer.
Inform the analyzer about that. Fixes the resulting false negatives.

rdar://problem/22280098

Differential Revision: https://reviews.llvm.org/D27409

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/test/Analysis/retain-release-arc.m

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=289047&r1=289046&r2=289047&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Thu Dec  8 08:05:48 2016
@@ -953,7 +953,10 @@ void RetainSummaryManager::updateSummary
       if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
         // When the CGBitmapContext is deallocated, the callback here will free
         // the associated data buffer.
-        if (Name->isStr("CGBitmapContextCreateWithData"))
+        // The callback in dispatch_data_create frees the buffer, but not
+        // the data object.
+        if (Name->isStr("CGBitmapContextCreateWithData") ||
+            Name->isStr("dispatch_data_create"))
           RE = S->getRetEffect();
       }
     }

Modified: cfe/trunk/test/Analysis/retain-release-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-arc.m?rev=289047&r1=289046&r2=289047&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release-arc.m (original)
+++ cfe/trunk/test/Analysis/retain-release-arc.m Thu Dec  8 08:05:48 2016
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fobjc-arc -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
 
+typedef __typeof(sizeof(int)) size_t;
+
 #define HAS_ARC __has_feature(objc_arc)
 
 typedef unsigned long long CFOptionFlags;
@@ -45,6 +47,41 @@ typedef struct _NSZone NSZone;
 @interface NSDictionary : NSObject
 @end
 
+#define OS_OBJECT_RETURNS_RETAINED __attribute__((__ns_returns_retained__))
+#define DISPATCH_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED
+
+ at protocol OS_dispatch_object
+ at end
+ at protocol OS_dispatch_data <OS_dispatch_object>
+ at end
+ at protocol OS_dispatch_queue <OS_dispatch_object>
+ at end
+
+typedef NSObject<OS_dispatch_object> *dispatch_object_t;
+typedef NSObject<OS_dispatch_data> *dispatch_data_t;
+typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+
+typedef void (^dispatch_block_t)(void);
+
+dispatch_queue_t dispatch_get_main_queue(void);
+
+DISPATCH_RETURNS_RETAINED dispatch_data_t
+dispatch_data_create(const void *buffer, size_t size,
+                     dispatch_queue_t _Nullable queue,
+                     dispatch_block_t _Nullable destructor);
+
+void _dispatch_object_validate(dispatch_object_t object);
+
+#define dispatch_retain(object) \
+  __extension__({ dispatch_object_t _o = (object); \
+                  _dispatch_object_validate(_o); \
+                  (void)[_o retain]; })
+#define dispatch_release(object) \
+  __extension__({ dispatch_object_t _o = (object); \
+                  _dispatch_object_validate(_o); \
+                  [_o release]; })
+
+
 @interface SomeClass
 @end
 
@@ -84,3 +121,46 @@ typedef struct _NSZone NSZone;
 }
 @end
 
+int buf[1024];
+
+void libdispatch_leaked_data() {
+  dispatch_data_t data = dispatch_data_create(buf, 1024,
+                                              dispatch_get_main_queue(), ^{});
+}
+#if !HAS_ARC
+  // expected-warning at -2{{Potential leak of an object stored into 'data'}}
+  // expected-note at -5{{Call to function 'dispatch_data_create' returns an Objective-C object with a +1 retain count}}
+  // expected-note at -4{{Object leaked: object allocated and stored into 'data' is not referenced later in this execution path and has a retain count of +1}}
+#endif
+
+void libdispatch_dispatch_released_data() {
+  dispatch_data_t data = dispatch_data_create(buf, 1024,
+                                              dispatch_get_main_queue(), ^{});
+#if !HAS_ARC
+  dispatch_release(data); // no-warning
+#endif
+}
+
+void libdispatch_objc_released_data() {
+  dispatch_data_t data = dispatch_data_create(buf, 1024,
+                                              dispatch_get_main_queue(), ^{});
+#if !HAS_ARC
+  [data release]; // no-warning
+#endif
+}
+
+void libdispatch_leaked_retained_data() {
+  dispatch_data_t data = dispatch_data_create(buf, 1024,
+                                              dispatch_get_main_queue(), ^{});
+#if !HAS_ARC
+  dispatch_retain(data);
+  [data release];
+#endif
+}
+#if !HAS_ARC
+// expected-warning at -2{{Potential leak of an object stored into 'data'}}
+// expected-note at -9{{Call to function 'dispatch_data_create' returns an Objective-C object with a +1 retain count}}
+// expected-note at -7{{Reference count incremented. The object now has a +2 retain count}}
+// expected-note at -7{{Reference count decremented. The object now has a +1 retain count}}
+// expected-note at -6{{Object leaked: object allocated and stored into 'data' is not referenced later in this execution path and has a retain count of +1}}
+#endif




More information about the cfe-commits mailing list