NoQ created this revision.
NoQ added reviewers: zaks.anna, dcoughlin.
NoQ added a subscriber: cfe-commits.

The hack that was previously applied to `CGBitmapContextCreateWithData()` is 
now extended to another function, `dispatch_data_create()`.

This function accepts a callback block, and the analyzer erroneously assumes 
that this callback may free up some data, which results in being unable to 
detect a leak of the `dispatch_data_t` object. In fact, the callback only frees 
the buffer that is passed into the function, but the returned object should be 
released separately unless in ARC mode.


https://reviews.llvm.org/D27409

Files:
  lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
  test/Analysis/dispatch-data-leak.m


Index: test/Analysis/dispatch-data-leak.m
===================================================================
--- /dev/null
+++ test/Analysis/dispatch-data-leak.m
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -w -triple x86_64-apple-macosx10.12.0 -fblocks -analyze 
-analyzer-checker=core,osx.cocoa,unix.Malloc -verify %s
+// RUN: %clang_cc1 -w -triple x86_64-apple-macosx10.12.0 -fblocks -fobjc-arc 
-analyze -analyzer-checker=core,osx.cocoa,unix.Malloc -verify %s
+
+#include "Inputs/system-header-simulator.h"
+#include "Inputs/system-header-simulator-objc.h"
+
+#define NON_ARC !__has_feature(objc_arc)
+
+#define DISPATCH_QUEUE_SERIAL NULL
+
+#define DISPATCH_DATA_DESTRUCTOR_DEFAULT NULL
+#define DISPATCH_DATA_DESTRUCTOR_FREE (_dispatch_data_destructor_free)
+#define DISPATCH_DATA_DESTRUCTOR_MUNMAP (_dispatch_data_destructor_munmap)
+
+#define OS_OBJECT_RETURNS_RETAINED __attribute__((__ns_returns_retained__))
+#define DISPATCH_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED
+
+@protocol OS_dispatch_data <NSObject>
+@end
+@protocol OS_dispatch_queue <NSObject>
+@end
+@protocol OS_dispatch_queue_attr <NSObject>
+@end
+
+typedef NSObject<OS_dispatch_data> *dispatch_data_t;
+typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+typedef NSObject<OS_dispatch_queue_attr> *dispatch_queue_attr_t;
+
+typedef void (^dispatch_block_t)(void);
+
+dispatch_queue_t dispatch_get_main_queue(void);
+
+DISPATCH_RETURNS_RETAINED dispatch_queue_t
+dispatch_queue_create(const char *_Nullable label,
+                      dispatch_queue_attr_t _Nullable attr);
+
+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 clang_analyzer_printState();
+
+char buf[1024];
+void find_all_three_leaks() {
+  char *malloc_buf;
+  dispatch_data_t data;
+  dispatch_queue_t q;
+
+  malloc_buf = malloc(1024);
+  data = dispatch_data_create(buf, 1024, dispatch_get_main_queue(), ^{}); // 
expected-warning{{Potential leak of memory pointed to by 'malloc_buf'}}
+#if NON_ARC
+  // expected-warning@-2{{Potential leak of an object stored into 'data'}}
+#endif
+  q = dispatch_queue_create("hello", DISPATCH_QUEUE_SERIAL);
+#if NON_ARC
+  // expected-warning@-2{{Potential leak of an object stored into 'q'}}
+#endif
+}
Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -953,7 +953,8 @@
       if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
         // When the CGBitmapContext is deallocated, the callback here will free
         // the associated data buffer.
-        if (Name->isStr("CGBitmapContextCreateWithData"))
+        if (Name->isStr("CGBitmapContextCreateWithData") ||
+            Name->isStr("dispatch_data_create"))
           RE = S->getRetEffect();
       }
     }


Index: test/Analysis/dispatch-data-leak.m
===================================================================
--- /dev/null
+++ test/Analysis/dispatch-data-leak.m
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -w -triple x86_64-apple-macosx10.12.0 -fblocks -analyze -analyzer-checker=core,osx.cocoa,unix.Malloc -verify %s
+// RUN: %clang_cc1 -w -triple x86_64-apple-macosx10.12.0 -fblocks -fobjc-arc -analyze -analyzer-checker=core,osx.cocoa,unix.Malloc -verify %s
+
+#include "Inputs/system-header-simulator.h"
+#include "Inputs/system-header-simulator-objc.h"
+
+#define NON_ARC !__has_feature(objc_arc)
+
+#define DISPATCH_QUEUE_SERIAL NULL
+
+#define DISPATCH_DATA_DESTRUCTOR_DEFAULT NULL
+#define DISPATCH_DATA_DESTRUCTOR_FREE (_dispatch_data_destructor_free)
+#define DISPATCH_DATA_DESTRUCTOR_MUNMAP (_dispatch_data_destructor_munmap)
+
+#define OS_OBJECT_RETURNS_RETAINED __attribute__((__ns_returns_retained__))
+#define DISPATCH_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED
+
+@protocol OS_dispatch_data <NSObject>
+@end
+@protocol OS_dispatch_queue <NSObject>
+@end
+@protocol OS_dispatch_queue_attr <NSObject>
+@end
+
+typedef NSObject<OS_dispatch_data> *dispatch_data_t;
+typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+typedef NSObject<OS_dispatch_queue_attr> *dispatch_queue_attr_t;
+
+typedef void (^dispatch_block_t)(void);
+
+dispatch_queue_t dispatch_get_main_queue(void);
+
+DISPATCH_RETURNS_RETAINED dispatch_queue_t
+dispatch_queue_create(const char *_Nullable label,
+                      dispatch_queue_attr_t _Nullable attr);
+
+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 clang_analyzer_printState();
+
+char buf[1024];
+void find_all_three_leaks() {
+  char *malloc_buf;
+  dispatch_data_t data;
+  dispatch_queue_t q;
+
+  malloc_buf = malloc(1024);
+  data = dispatch_data_create(buf, 1024, dispatch_get_main_queue(), ^{}); // expected-warning{{Potential leak of memory pointed to by 'malloc_buf'}}
+#if NON_ARC
+  // expected-warning@-2{{Potential leak of an object stored into 'data'}}
+#endif
+  q = dispatch_queue_create("hello", DISPATCH_QUEUE_SERIAL);
+#if NON_ARC
+  // expected-warning@-2{{Potential leak of an object stored into 'q'}}
+#endif
+}
Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -953,7 +953,8 @@
       if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
         // When the CGBitmapContext is deallocated, the callback here will free
         // the associated data buffer.
-        if (Name->isStr("CGBitmapContextCreateWithData"))
+        if (Name->isStr("CGBitmapContextCreateWithData") ||
+            Name->isStr("dispatch_data_create"))
           RE = S->getRetEffect();
       }
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to