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