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