1// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s 2// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file %s -o %t 3// RUN: %normalize_plist <%t | diff -ub %S/Inputs/expected-plists/retain-release-path-notes.m.plist - 4 5/*** 6This file is for testing the path-sensitive notes for retain/release errors. 7Its goal is to have simple branch coverage of any path-based diagnostics, 8not to actually check all possible retain/release errors. 9 10This file includes notes that only appear in a ref-counted analysis. 11GC-specific notes should go in retain-release-path-notes-gc.m. 12***/ 13 14@interface NSObject 15+ (id)alloc; 16- (id)init; 17- (void)dealloc; 18 19- (Class)class; 20 21- (id)retain; 22- (void)release; 23- (void)autorelease; 24@end 25 26@interface Foo : NSObject 27- (id)methodWithValue; 28@property(retain) id propertyValue; 29 30- (id)objectAtIndexedSubscript:(unsigned)index; 31- (id)objectForKeyedSubscript:(id)key; 32@end 33 34typedef struct CFType *CFTypeRef; 35CFTypeRef CFRetain(CFTypeRef); 36void CFRelease(CFTypeRef); 37CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed))); 38 39id NSMakeCollectable(CFTypeRef); 40CFTypeRef CFMakeCollectable(CFTypeRef); 41 42CFTypeRef CFCreateSomething(); 43CFTypeRef CFGetSomething(); 44 45 46void creationViaAlloc () { 47 id leaked = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}} 48 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 49} 50 51void creationViaCFCreate () { 52 CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}} 53 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 54} 55 56void acquisitionViaMethod (Foo *foo) { 57 id leaked = [foo methodWithValue]; // expected-note{{Method returns an Objective-C object with a +0 retain count}} 58 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} 59 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}} 60 [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}} 61 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 62} 63 64void acquisitionViaProperty (Foo *foo) { 65 id leaked = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} 66 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} 67 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 68} 69 70void acquisitionViaCFFunction () { 71 CFTypeRef leaked = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}} 72 CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}} 73 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 74} 75 76void explicitDealloc () { 77 id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}} 78 [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}} 79 [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} 80} 81 82void implicitDealloc () { 83 id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}} 84 [object release]; // expected-note{{Object released}} 85 [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} 86} 87 88void overAutorelease () { 89 id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}} 90 [object autorelease]; // expected-note{{Object autoreleased}} 91 [object autorelease]; // expected-note{{Object autoreleased}} 92 return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +1 retain count}} 93} 94 95void autoreleaseUnowned (Foo *foo) { 96 id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} 97 [object autorelease]; // expected-note{{Object autoreleased}} 98 return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased but has a +0 retain count}} 99} 100 101void makeCollectableIgnored() { 102 CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}} 103 CFMakeCollectable(leaked); 104 NSMakeCollectable(leaked); 105 return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} 106} 107 108CFTypeRef CFCopyRuleViolation () { 109 CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}} 110 return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 111} 112 113CFTypeRef CFGetRuleViolation () { 114 CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}} 115 return object; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}} 116} 117 118@implementation Foo (FundamentalMemoryManagementRules) 119- (id)copyViolation { 120 id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} 121 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 122} 123 124- (id)copyViolationIndexedSubscript { 125 id result = self[0]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}} 126 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 127} 128 129- (id)copyViolationKeyedSubscript { 130 id result = self[self]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}} 131 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 132} 133 134- (id)getViolation { 135 id result = [[Foo alloc] init]; // expected-note{{Method returns an instance of Foo with a +1 retain count}} 136 return result; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}} 137} 138 139- (id)copyAutorelease { 140 id result = [[Foo alloc] init]; // expected-note{{Method returns an instance of Foo with a +1 retain count}} 141 [result autorelease]; // expected-note{{Object autoreleased}} 142 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 143} 144@end 145 146 147typedef unsigned long NSUInteger; 148 149@interface NSValue : NSObject 150@end 151 152@interface NSNumber : NSValue 153+ (NSNumber *)numberWithInt:(int)i; 154@end 155 156@interface NSString : NSObject 157+ (NSString *)stringWithUTF8String:(const char *)str; 158@end 159 160@interface NSArray : NSObject 161+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count; 162@end 163 164@interface NSDictionary : NSObject 165+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count; 166@end 167 168 169void testNumericLiteral() { 170 id result = @1; // expected-note{{NSNumber literal is an object with a +0 retain count}} 171 [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 172} 173 174void testBoxedInt(int x) { 175 id result = @(x); // expected-note{{NSNumber boxed expression produces an object with a +0 retain count}} 176 [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 177} 178 179void testBoxedString(const char *str) { 180 id result = @(str); // expected-note{{NSString boxed expression produces an object with a +0 retain count}} 181 [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 182} 183 184void testArray(id obj) { 185 id result = @[obj]; // expected-note{{NSArray literal is an object with a +0 retain count}} 186 [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 187} 188 189void testDictionary(id key, id value) { 190 id result = @{key: value}; // expected-note{{NSDictionary literal is an object with a +0 retain count}} 191 [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 192} 193 194// Test that we step into the init method when the allocated object is leaked due to early escape within init. 195 196static int Cond; 197@interface MyObj : NSObject 198-(id)initX; 199-(id)initY; 200-(id)initZ; 201+(void)test; 202@end 203 204@implementation MyObj 205 206-(id)initX { 207 if (Cond) // expected-note {{Assuming 'Cond' is not equal to 0}} 208 // expected-note@-1{{Taking true branch}} 209 return 0; 210 self = [super init]; 211 return self; 212} 213 214-(id)initY { 215 self = [super init]; //expected-note {{Method returns an instance of MyObj with a +1 retain count}} 216 return self; 217} 218 219-(id)initZ { 220 self = [super init]; 221 return self; 222} 223 224+(void)test { 225 // initX is inlined since we explicitly mark it as interesting 226 id x = [[MyObj alloc] initX]; // expected-warning {{Potential leak of an object}} 227 // expected-note@-1 {{Method returns an instance of MyObj with a +1 retain count}} 228 // expected-note@-2 {{Calling 'initX'}} 229 // expected-note@-3 {{Returning from 'initX'}} 230 // expected-note@-4 {{Object leaked: allocated object of type 'MyObj *' is not referenced later in this execution path and has a retain count of +1}} 231 // initI is inlined because the allocation happens within initY 232 id y = [[MyObj alloc] initY]; 233 // expected-note@-1 {{Calling 'initY'}} 234 // expected-note@-2 {{Returning from 'initY'}} 235 236 // initZ is not inlined 237 id z = [[MyObj alloc] initZ]; // expected-warning {{Potential leak of an object}} 238 // expected-note@-1 {{Object leaked: object allocated and stored into 'y' is not referenced later in this execution path and has a retain count of +1}} 239 240 [x release]; 241 [z release]; 242} 243@end 244 245 246void CFOverAutorelease() { 247 CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}} 248 CFAutorelease(object); // expected-note{{Object autoreleased}} 249 CFAutorelease(object); // expected-note{{Object autoreleased}} 250 return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +1 retain count}} 251} 252 253void CFAutoreleaseUnowned() { 254 CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}} 255 CFAutorelease(object); // expected-note{{Object autoreleased}} 256 return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased but has a +0 retain count}} 257} 258 259void CFAutoreleaseUnownedMixed() { 260 CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}} 261 CFAutorelease(object); // expected-note{{Object autoreleased}} 262 [(id)object autorelease]; // expected-note{{Object autoreleased}} 263 return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +0 retain count}} 264} 265 266@interface PropertiesAndIvars : NSObject 267@property (strong) id ownedProp; 268@property (unsafe_unretained) id unownedProp; 269@property (nonatomic, strong) id manualProp; 270@end 271 272@interface NSObject (PropertiesAndIvarsHelper) 273- (void)myMethod; 274@end 275 276@implementation PropertiesAndIvars { 277 id _ivarOnly; 278} 279 280- (id)manualProp { 281 return _manualProp; 282} 283 284- (void)testOverreleaseUnownedIvar { 285 [_unownedProp retain]; // FIXME-note {{Object loaded from instance variable}} 286 // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} 287 [_unownedProp release]; // FIXME-note {{Reference count decremented}} 288 [_unownedProp release]; // FIXME-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 289 // FIXME-warning@-1 {{not owned at this point by the caller}} 290} 291 292- (void)testOverreleaseOwnedIvarUse { 293 [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}} 294 // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} 295 [_ownedProp release]; // FIXME-note {{Reference count decremented}} 296 [_ownedProp release]; // FIXME-note {{Strong instance variable relinquished. Object released}} 297 [_ownedProp myMethod]; // FIXME-note {{Reference-counted object is used after it is released}} 298 // FIXME-warning@-1 {{used after it is released}} 299} 300 301- (void)testOverreleaseIvarOnlyUse { 302 [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}} 303 // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} 304 [_ivarOnly release]; // FIXME-note {{Reference count decremented}} 305 [_ivarOnly release]; // FIXME-note {{Strong instance variable relinquished. Object released}} 306 [_ivarOnly myMethod]; // FIXME-note {{Reference-counted object is used after it is released}} 307 // FIXME-warning@-1 {{used after it is released}} 308} 309 310- (void)testOverreleaseOwnedIvarAutorelease { 311 [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}} 312 // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} 313 [_ownedProp release]; // FIXME-note {{Reference count decremented}} 314 [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}} 315 [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}} 316 // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}} 317} // FIXME-warning{{Object autoreleased too many times}} 318 319- (void)testOverreleaseIvarOnlyAutorelease { 320 [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}} 321 // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} 322 [_ivarOnly release]; // FIXME-note {{Reference count decremented}} 323 [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}} 324 [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}} 325 // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}} 326} // FIXME-warning{{Object autoreleased too many times}} 327 328@end 329 330 331 332