1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s |
2 | |
3 | void clang_analyzer_warnIfReached(); |
4 | |
5 | #define nil ((id)0) |
6 | |
7 | typedef unsigned long NSUInteger; |
8 | @protocol NSObject |
9 | - (instancetype)retain; |
10 | - (oneway void)release; |
11 | @end |
12 | |
13 | @interface NSObject <NSObject> { } |
14 | - (void)dealloc; |
15 | - (instancetype)init; |
16 | @end |
17 | |
18 | typedef struct objc_selector *SEL; |
19 | |
20 | //===------------------------------------------------------------------------=== |
21 | // <rdar://problem/6953275> |
22 | // Check that 'self' is not referenced after calling '[super dealloc]'. |
23 | |
24 | @interface SuperDeallocThenReleaseIvarClass : NSObject { |
25 | NSObject *_ivar; |
26 | } |
27 | @end |
28 | |
29 | @implementation SuperDeallocThenReleaseIvarClass |
30 | - (instancetype)initWithIvar:(NSObject *)ivar { |
31 | self = [super init]; |
32 | if (!self) |
33 | return nil; |
34 | _ivar = [ivar retain]; |
35 | return self; |
36 | } |
37 | - (void)dealloc { |
38 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
39 | [_ivar release]; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
40 | // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
41 | } |
42 | @end |
43 | |
44 | @interface SuperDeallocThenAssignNilToIvarClass : NSObject { |
45 | NSObject *_delegate; |
46 | } |
47 | @end |
48 | |
49 | @implementation SuperDeallocThenAssignNilToIvarClass |
50 | - (instancetype)initWithDelegate:(NSObject *)delegate { |
51 | self = [super init]; |
52 | if (!self) |
53 | return nil; |
54 | _delegate = delegate; |
55 | return self; |
56 | } |
57 | - (void)dealloc { |
58 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
59 | _delegate = nil; // expected-warning {{Use of instance variable '_delegate' after 'self' has been deallocated}} |
60 | // expected-note@-1 {{Use of instance variable '_delegate' after 'self' has been deallocated}} |
61 | } |
62 | @end |
63 | |
64 | |
65 | struct SomeStruct { |
66 | int f; |
67 | }; |
68 | |
69 | @interface SuperDeallocThenAssignIvarField : NSObject { |
70 | struct SomeStruct _s; |
71 | } |
72 | @end |
73 | |
74 | @implementation SuperDeallocThenAssignIvarField |
75 | - (void)dealloc { |
76 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
77 | _s.f = 7; // expected-warning {{Use of instance variable '_s' after 'self' has been deallocated}} |
78 | // expected-note@-1 {{Use of instance variable '_s' after 'self' has been deallocated}} |
79 | } |
80 | @end |
81 | |
82 | @interface OtherClassWithIvar { |
83 | @public |
84 | int _otherIvar; |
85 | } |
86 | @end; |
87 | |
88 | @interface SuperDeallocThenAssignIvarIvar : NSObject { |
89 | OtherClassWithIvar *_ivar; |
90 | } |
91 | @end |
92 | |
93 | @implementation SuperDeallocThenAssignIvarIvar |
94 | - (void)dealloc { |
95 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
96 | _ivar->_otherIvar = 7; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
97 | // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
98 | } |
99 | @end |
100 | |
101 | @interface SuperDeallocThenAssignSelfIvar : NSObject { |
102 | NSObject *_ivar; |
103 | } |
104 | @end |
105 | |
106 | @implementation SuperDeallocThenAssignSelfIvar |
107 | - (void)dealloc { |
108 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
109 | self->_ivar = nil; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
110 | // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} |
111 | } |
112 | @end |
113 | |
114 | @interface SuperDeallocThenReleasePropertyClass : NSObject { } |
115 | @property (retain) NSObject *ivar; |
116 | @end |
117 | |
118 | @implementation SuperDeallocThenReleasePropertyClass |
119 | - (instancetype)initWithProperty:(NSObject *)ivar { |
120 | self = [super init]; |
121 | if (!self) |
122 | return nil; |
123 | self.ivar = ivar; |
124 | return self; |
125 | } |
126 | - (void)dealloc { |
127 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
128 | self.ivar = nil; // expected-warning {{Use of 'self' after it has been deallocated}} |
129 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
130 | } |
131 | @end |
132 | |
133 | @interface SuperDeallocThenAssignNilToPropertyClass : NSObject { } |
134 | @property (assign) NSObject *delegate; |
135 | @end |
136 | |
137 | @implementation SuperDeallocThenAssignNilToPropertyClass |
138 | - (instancetype)initWithDelegate:(NSObject *)delegate { |
139 | self = [super init]; |
140 | if (!self) |
141 | return nil; |
142 | self.delegate = delegate; |
143 | return self; |
144 | } |
145 | - (void)dealloc { |
146 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
147 | self.delegate = nil; // expected-warning {{Use of 'self' after it has been deallocated}} |
148 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
149 | } |
150 | @end |
151 | |
152 | @interface SuperDeallocThenCallInstanceMethodClass : NSObject { } |
153 | - (void)_invalidate; |
154 | @end |
155 | |
156 | @implementation SuperDeallocThenCallInstanceMethodClass |
157 | - (void)_invalidate { |
158 | } |
159 | - (void)dealloc { |
160 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
161 | [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}} |
162 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
163 | } |
164 | @end |
165 | |
166 | @interface SuperDeallocThenCallNonObjectiveCMethodClass : NSObject { } |
167 | @end |
168 | |
169 | static void _invalidate(NSObject *object) { |
170 | (void)object; |
171 | } |
172 | |
173 | @implementation SuperDeallocThenCallNonObjectiveCMethodClass |
174 | - (void)dealloc { |
175 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
176 | _invalidate(self); // expected-warning {{Use of 'self' after it has been deallocated}} |
177 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
178 | } |
179 | @end |
180 | |
181 | @interface SuperDeallocThenCallObjectiveClassMethodClass : NSObject { } |
182 | @end |
183 | |
184 | @implementation SuperDeallocThenCallObjectiveClassMethodClass |
185 | + (void) invalidate:(id)arg; { |
186 | } |
187 | |
188 | - (void)dealloc { |
189 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
190 | [SuperDeallocThenCallObjectiveClassMethodClass invalidate:self]; // expected-warning {{Use of 'self' after it has been deallocated}} |
191 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
192 | } |
193 | @end |
194 | |
195 | @interface TwoSuperDeallocCallsClass : NSObject { |
196 | NSObject *_ivar; |
197 | } |
198 | - (void)_invalidate; |
199 | @end |
200 | |
201 | @implementation TwoSuperDeallocCallsClass |
202 | - (void)_invalidate { |
203 | } |
204 | - (void)dealloc { |
205 | if (_ivar) { // expected-note {{Assuming the condition is false}} expected-note {{Taking false branch}} |
206 | [_ivar release]; |
207 | [super dealloc]; |
208 | return; |
209 | } |
210 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
211 | [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}} |
212 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
213 | } |
214 | @end |
215 | |
216 | //===------------------------------------------------------------------------=== |
217 | // Warn about calling [super dealloc] twice due to missing return statement. |
218 | |
219 | @interface MissingReturnCausesDoubleSuperDeallocClass : NSObject { |
220 | NSObject *_ivar; |
221 | } |
222 | @end |
223 | |
224 | @implementation MissingReturnCausesDoubleSuperDeallocClass |
225 | - (void)dealloc { |
226 | if (_ivar) { // expected-note {{Assuming the condition is true}} expected-note {{Taking true branch}} |
227 | [_ivar release]; |
228 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
229 | // return; |
230 | } |
231 | [super dealloc]; // expected-warning{{[super dealloc] should not be called multiple times}} |
232 | // expected-note@-1{{[super dealloc] should not be called multiple times}} |
233 | } |
234 | @end |
235 | |
236 | //===------------------------------------------------------------------------=== |
237 | // Warn about calling [super dealloc] twice in two different methods. |
238 | |
239 | @interface SuperDeallocInOtherMethodClass : NSObject { |
240 | NSObject *_ivar; |
241 | } |
242 | - (void)_cleanup; |
243 | @end |
244 | |
245 | @implementation SuperDeallocInOtherMethodClass |
246 | - (void)_cleanup { |
247 | [_ivar release]; |
248 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
249 | } |
250 | - (void)dealloc { |
251 | [self _cleanup]; // expected-note {{Calling '_cleanup'}} |
252 | //expected-note@-1 {{Returning from '_cleanup'}} |
253 | [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}} |
254 | // expected-note@-1 {{[super dealloc] should not be called multiple times}} |
255 | } |
256 | @end |
257 | |
258 | //===------------------------------------------------------------------------=== |
259 | // Do not warn about calling [super dealloc] recursively for different objects |
260 | // of the same type with custom retain counting. |
261 | // |
262 | // A class that contains an ivar of itself with custom retain counting (such |
263 | // as provided by _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN) can generate |
264 | // a false positive that [super dealloc] is called twice if each object instance |
265 | // is not tracked separately by the checker. This test case is just a simple |
266 | // approximation to trigger the false positive. |
267 | |
268 | @class ClassWithOwnIvarInstanceClass; |
269 | @interface ClassWithOwnIvarInstanceClass : NSObject { |
270 | ClassWithOwnIvarInstanceClass *_ivar; |
271 | NSUInteger _retainCount; |
272 | } |
273 | @end |
274 | |
275 | @implementation ClassWithOwnIvarInstanceClass |
276 | - (instancetype)retain { |
277 | ++_retainCount; |
278 | return self; |
279 | } |
280 | - (oneway void)release { |
281 | --_retainCount; |
282 | if (!_retainCount) |
283 | [self dealloc]; |
284 | } |
285 | - (void)dealloc { |
286 | [_ivar release]; |
287 | [super dealloc]; // no warning: different instances of same class |
288 | } |
289 | @end |
290 | |
291 | //===------------------------------------------------------------------------=== |
292 | // Do not warn about calling [super dealloc] twice if +dealloc is a class |
293 | // method. |
294 | |
295 | @interface SuperDeallocClassMethodIgnoredClass : NSObject { } |
296 | + (void)dealloc; |
297 | @end |
298 | |
299 | @implementation SuperDeallocClassMethodIgnoredClass |
300 | + (void)dealloc { } |
301 | @end |
302 | |
303 | @interface SuperDeallocClassMethodIgnoredSubClass : NSObject { } |
304 | + (void)dealloc; |
305 | @end |
306 | |
307 | @implementation SuperDeallocClassMethodIgnoredSubClass |
308 | + (void)dealloc { |
309 | [super dealloc]; |
310 | [super dealloc]; // no warning: class method |
311 | } |
312 | @end |
313 | |
314 | //===------------------------------------------------------------------------=== |
315 | // Do not warn about calling [super dealloc] twice if when the analyzer has |
316 | // inlined the call to its super deallocator. |
317 | |
318 | @interface SuperClassCallingSuperDealloc : NSObject { |
319 | NSObject *_ivar; |
320 | } |
321 | @end |
322 | |
323 | @implementation SuperClassCallingSuperDealloc |
324 | - (void)dealloc; { |
325 | [_ivar release]; // no-warning |
326 | |
327 | [super dealloc]; |
328 | } |
329 | @end |
330 | |
331 | @interface SubclassCallingSuperDealloc : SuperClassCallingSuperDealloc |
332 | @end |
333 | |
334 | @implementation SubclassCallingSuperDealloc |
335 | - (void)dealloc; { |
336 | [super dealloc]; |
337 | } |
338 | @end |
339 | |
340 | //===------------------------------------------------------------------------=== |
341 | // Treat calling [super dealloc] twice as as a sink. |
342 | |
343 | @interface CallingSuperDeallocTwiceIsSink : NSObject |
344 | @end |
345 | |
346 | @implementation CallingSuperDeallocTwiceIsSink |
347 | - (void)dealloc; { |
348 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
349 | [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}} |
350 | // expected-note@-1 {{[super dealloc] should not be called multiple times}} |
351 | |
352 | clang_analyzer_warnIfReached(); // no-warning |
353 | } |
354 | @end |
355 | |
356 | |
357 | //===------------------------------------------------------------------------=== |
358 | // Test path notes with intervening method call on self. |
359 | |
360 | @interface InterveningMethodCallOnSelf : NSObject |
361 | @end |
362 | |
363 | @implementation InterveningMethodCallOnSelf |
364 | - (void)anotherMethod { |
365 | } |
366 | |
367 | - (void)dealloc; { |
368 | [super dealloc]; // expected-note {{[super dealloc] called here}} |
369 | [self anotherMethod]; // expected-warning {{Use of 'self' after it has been deallocated}} |
370 | // expected-note@-1 {{Use of 'self' after it has been deallocated}} |
371 | [super dealloc]; |
372 | } |
373 | @end |
374 | |