150
|
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
|