1// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s 2 3void clang_analyzer_warnIfReached(); 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// <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 65struct 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 169static 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 {{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 {{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