blob: 5b702214a4826a79fb4c4f91a2433a648c776626 [file] [log] [blame]
Jordy Rose17a38e22011-09-02 05:55:19 +00001// 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
Jordy Rose5b5402b2011-07-15 22:17:54 +00002
Jordy Rose5b5402b2011-07-15 22:17:54 +00003/***
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;
Jordan Rose8919e682012-07-18 21:59:51 +000027
28- (id)objectAtIndexedSubscript:(unsigned)index;
29- (id)objectForKeyedSubscript:(id)key;
Jordy Rose5b5402b2011-07-15 22:17:54 +000030@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 () {
Richard Trieu2fe9b7f2011-12-15 00:38:15 +0000106 CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
Jordy Rose5b5402b2011-07-15 22:17:54 +0000107 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 () {
Richard Trieu2fe9b7f2011-12-15 00:38:15 +0000111 CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
Ted Kremenekb7dcddf2011-12-22 06:35:52 +0000112 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}}
Jordy Rose5b5402b2011-07-15 22:17:54 +0000113}
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
Jordan Rose8919e682012-07-18 21:59:51 +0000121- (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
Jordy Rose5b5402b2011-07-15 22:17:54 +0000131- (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}
Jordy Rose74b7b2b2012-03-17 05:49:15 +0000135
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}
Jordy Rose5b5402b2011-07-15 22:17:54 +0000141@end
Jordy Rose70fdbc32012-05-12 05:10:43 +0000142
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}