Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -953,7 +953,10 @@ 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(); } } 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 +@end +@protocol OS_dispatch_queue +@end +@protocol OS_dispatch_queue_attr +@end + +typedef NSObject *dispatch_data_t; +typedef NSObject *dispatch_queue_t; +typedef NSObject *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 +}