Index: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ cfe/trunk/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: cfe/trunk/test/Analysis/retain-release-arc.m =================================================================== --- cfe/trunk/test/Analysis/retain-release-arc.m +++ cfe/trunk/test/Analysis/retain-release-arc.m @@ -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 @@ @interface NSDictionary : NSObject @end +#define OS_OBJECT_RETURNS_RETAINED __attribute__((__ns_returns_retained__)) +#define DISPATCH_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED + +@protocol OS_dispatch_object +@end +@protocol OS_dispatch_data +@end +@protocol OS_dispatch_queue +@end + +typedef NSObject *dispatch_object_t; +typedef NSObject *dispatch_data_t; +typedef NSObject *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 @@ } @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@-2{{Potential leak of an object stored into 'data'}} + // expected-note@-5{{Call to function 'dispatch_data_create' returns an Objective-C object with a +1 retain count}} + // expected-note@-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@-2{{Potential leak of an object stored into 'data'}} +// expected-note@-9{{Call to function 'dispatch_data_create' returns an Objective-C object with a +1 retain count}} +// expected-note@-7{{Reference count incremented. The object now has a +2 retain count}} +// expected-note@-7{{Reference count decremented. The object now has a +1 retain count}} +// expected-note@-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