1 // RUN: %clang_cc1 -analyze -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 {{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