retain-release-path-notes.m revision 8919e688dc610d1f632a4d43f7f1489f67255476
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s 2 3/*** 4This file is for testing the path-sensitive notes for retain/release errors. 5Its goal is to have simple branch coverage of any path-based diagnostics, 6not to actually check all possible retain/release errors. 7 8This file includes notes that only appear in a ref-counted analysis. 9GC-specific notes should go in retain-release-path-notes-gc.m. 10***/ 11 12@interface NSObject 13+ (id)alloc; 14- (id)init; 15- (void)dealloc; 16 17- (Class)class; 18 19- (id)retain; 20- (void)release; 21- (void)autorelease; 22@end 23 24@interface Foo : NSObject 25- (id)methodWithValue; 26@property(retain) id propertyValue; 27 28- (id)objectAtIndexedSubscript:(unsigned)index; 29- (id)objectForKeyedSubscript:(id)key; 30@end 31 32typedef struct CFType *CFTypeRef; 33CFTypeRef CFRetain(CFTypeRef); 34void CFRelease(CFTypeRef); 35 36id NSMakeCollectable(CFTypeRef); 37CFTypeRef CFMakeCollectable(CFTypeRef); 38 39CFTypeRef CFCreateSomething(); 40CFTypeRef CFGetSomething(); 41 42 43void creationViaAlloc () { 44 id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} 45 return; // 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}} 46} 47 48void creationViaCFCreate () { 49 CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} 50 return; // 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}} 51} 52 53void acquisitionViaMethod (Foo *foo) { 54 id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}} 55 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} 56 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}} 57 [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}} 58 return; // 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}} 59} 60 61void acquisitionViaProperty (Foo *foo) { 62 id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}} 63 [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} 64 return; // 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}} 65} 66 67void acquisitionViaCFFunction () { 68 CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} 69 CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}} 70 return; // 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}} 71} 72 73void explicitDealloc () { 74 id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} 75 [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}} 76 [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} 77} 78 79void implicitDealloc () { 80 id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} 81 [object release]; // expected-note{{Object released}} 82 [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} 83} 84 85void overAutorelease () { 86 id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} 87 [object autorelease]; // expected-note{{Object sent -autorelease message}} 88 [object autorelease]; // expected-note{{Object sent -autorelease message}} 89 return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}} 90} 91 92void autoreleaseUnowned (Foo *foo) { 93 id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} 94 [object autorelease]; // expected-note{{Object sent -autorelease message}} 95 return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}} 96} 97 98void makeCollectableIgnored () { 99 CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} 100 CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}} 101 NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}} 102 return; // 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}} 103} 104 105CFTypeRef CFCopyRuleViolation () { 106 CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} 107 return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 108} 109 110CFTypeRef CFGetRuleViolation () { 111 CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} 112 return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} 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}} 113} 114 115@implementation Foo (FundamentalMemoryManagementRules) 116- (id)copyViolation { 117 id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} 118 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 119} 120 121- (id)copyViolationIndexedSubscript { 122 id result = self[0]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}} 123 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 124} 125 126- (id)copyViolationKeyedSubscript { 127 id result = self[self]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}} 128 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 129} 130 131- (id)getViolation { 132 id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} 133 return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} 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}} 134} 135 136- (id)copyAutorelease { 137 id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} 138 [result autorelease]; // expected-note{{Object sent -autorelease message}} 139 return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} 140} 141@end 142 143 144typedef unsigned long NSUInteger; 145 146@interface NSValue : NSObject 147@end 148 149@interface NSNumber : NSValue 150+ (NSNumber *)numberWithInt:(int)i; 151@end 152 153@interface NSString : NSObject 154+ (NSString *)stringWithUTF8String:(const char *)str; 155@end 156 157@interface NSArray : NSObject 158+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count; 159@end 160 161@interface NSDictionary : NSObject 162+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count; 163@end 164 165 166void testNumericLiteral() { 167 id result = @1; // expected-note{{NSNumber literal is an object with a +0 retain count}} 168 [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}} 169} 170 171void testBoxedInt(int x) { 172 id result = @(x); // expected-note{{NSNumber boxed expression produces an object with a +0 retain count}} 173 [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}} 174} 175 176void testBoxedString(const char *str) { 177 id result = @(str); // expected-note{{NSString boxed expression produces an object with a +0 retain count}} 178 [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}} 179} 180 181void testArray(id obj) { 182 id result = @[obj]; // expected-note{{NSArray literal is an object with a +0 retain count}} 183 [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}} 184} 185 186void testDictionary(id key, id value) { 187 id result = @{key: value}; // expected-note{{NSDictionary literal is an object with a +0 retain count}} 188 [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}} 189} 190