Home | History | Annotate | Download | only in Analysis
      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