Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
      2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
      3 
      4 void clang_analyzer_eval(int);
      5 
      6 typedef const void * CFTypeRef;
      7 extern CFTypeRef CFRetain(CFTypeRef cf);
      8 void CFRelease(CFTypeRef cf);
      9 
     10 typedef signed char BOOL;
     11 typedef unsigned int NSUInteger;
     12 typedef struct _NSZone NSZone;
     13 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
     14 @protocol NSObject  - (BOOL)isEqual:(id)object; @end
     15 @protocol NSCopying  - (id)copyWithZone:(NSZone *)zone; @end
     16 @protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder; @end
     17 @protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone; @end
     18 @interface NSObject <NSObject> {}
     19 +(id)alloc;
     20 -(id)init;
     21 -(id)autorelease;
     22 -(id)copy;
     23 -(id)retain;
     24 -(oneway void)release;
     25 @end
     26 @interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
     27 - (NSUInteger)length;
     28 -(id)initWithFormat:(NSString *)f,...;
     29 -(BOOL)isEqualToString:(NSString *)s;
     30 + (id)string;
     31 @end
     32 @interface NSNumber : NSObject {}
     33 +(id)alloc;
     34 -(id)initWithInteger:(int)i;
     35 @end
     36 
     37 // rdar://6946338
     38 
     39 @interface Test1 : NSObject {
     40   NSString *text;
     41 }
     42 -(id)myMethod;
     43 @property (nonatomic, assign) NSString *text;
     44 @end
     45 
     46 
     47 #if !__has_feature(objc_arc)
     48 
     49 @implementation Test1
     50 
     51 @synthesize text;
     52 
     53 -(id)myMethod {
     54   Test1 *cell = [[[Test1 alloc] init] autorelease];
     55 
     56   NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
     57   cell.text = string1;
     58 
     59   return cell;
     60 }
     61 
     62 @end
     63 
     64 
     65 // rdar://8824416
     66 
     67 @interface MyNumber : NSObject
     68 {
     69   NSNumber* _myNumber;
     70 }
     71 
     72 - (id)initWithNumber:(NSNumber *)number;
     73 
     74 @property (nonatomic, readonly) NSNumber* myNumber;
     75 @property (nonatomic, readonly) NSNumber* newMyNumber;
     76 
     77 @end
     78 
     79 @implementation MyNumber
     80 @synthesize myNumber=_myNumber;
     81  
     82 - (id)initWithNumber:(NSNumber *)number
     83 {
     84   self = [super init];
     85   
     86   if ( self )
     87   {
     88     _myNumber = [number copy];
     89   }
     90   
     91   return self;
     92 }
     93 
     94 - (NSNumber*)newMyNumber
     95 {
     96   if ( _myNumber )
     97     return [_myNumber retain];
     98   
     99   return [[NSNumber alloc] initWithInteger:1];
    100 }
    101 
    102 - (id)valueForUndefinedKey:(NSString*)key
    103 {
    104   id value = 0;
    105   
    106   if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
    107     value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
    108   else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
    109     value = [self.myNumber retain]; // this line fixes the over release
    110   else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
    111     value = self.newMyNumber; // this one is ok, since value is returned retained
    112   else 
    113     value = [[NSNumber alloc] initWithInteger:0];
    114   
    115   return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
    116 }
    117 
    118 @end
    119 
    120 NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
    121 {
    122   NSNumber* result = aMyNumber.myNumber;
    123     
    124   return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
    125 }
    126 
    127 #endif
    128 
    129 
    130 // rdar://6611873
    131 
    132 @interface Person : NSObject {
    133   NSString *_name;
    134 }
    135 @property (retain) NSString * name;
    136 @property (assign) id friend;
    137 @end
    138 
    139 @implementation Person
    140 @synthesize name = _name;
    141 @end
    142 
    143 #if !__has_feature(objc_arc)
    144 void rdar6611873() {
    145   Person *p = [[[Person alloc] init] autorelease];
    146   
    147   p.name = [[NSString string] retain]; // expected-warning {{leak}}
    148   p.name = [[NSString alloc] init]; // expected-warning {{leak}}
    149 
    150   p.friend = [[Person alloc] init]; // expected-warning {{leak}}
    151 }
    152 #endif
    153 
    154 @interface SubPerson : Person
    155 -(NSString *)foo;
    156 @end
    157 
    158 @implementation SubPerson
    159 -(NSString *)foo {
    160   return super.name;
    161 }
    162 @end
    163 
    164 
    165 #if !__has_feature(objc_arc)
    166 // <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
    167 @interface RDar9241180
    168 @property (readwrite,assign) id x;
    169 -(id)testAnalyzer1:(int) y;
    170 -(void)testAnalyzer2;
    171 @end
    172 
    173 @implementation RDar9241180
    174 @synthesize x;
    175 -(id)testAnalyzer1:(int)y {
    176     RDar9241180 *o;
    177     if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
    178       return o;
    179     return o; // expected-warning {{Undefined or garbage value returned to caller}}
    180 }
    181 -(void)testAnalyzer2 {
    182   id y;
    183   self.x = y;  // expected-warning {{Argument for property setter is an uninitialized value}}
    184 }
    185 @end
    186 #endif
    187 
    188 
    189 //------
    190 // Property accessor synthesis
    191 //------
    192 
    193 extern void doSomethingWithPerson(Person *p);
    194 extern void doSomethingWithName(NSString *name);
    195 
    196 void testConsistencyRetain(Person *p) {
    197   clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
    198 
    199   id origName = p.name;
    200   clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
    201   doSomethingWithPerson(p);
    202   clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
    203 }
    204 
    205 void testConsistencyAssign(Person *p) {
    206   clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
    207 
    208   id origFriend = p.friend;
    209   clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
    210   doSomethingWithPerson(p);
    211   clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
    212 }
    213 
    214 #if !__has_feature(objc_arc)
    215 void testOverrelease(Person *p, int coin) {
    216   switch (coin) {
    217   case 0:
    218     [p.name release]; // expected-warning{{not owned}}
    219     break;
    220   case 1:
    221     [p.friend release]; // expected-warning{{not owned}}
    222     break;
    223   case 2: {
    224     id friend = p.friend;
    225     doSomethingWithPerson(p);
    226     [friend release]; // expected-warning{{not owned}}
    227   }
    228   }
    229 }
    230 
    231 // <rdar://problem/16333368>
    232 @implementation Person (Rdar16333368)
    233 
    234 - (void)testDeliberateRelease:(Person *)other {
    235   doSomethingWithName(self.name);
    236   [_name release]; // no-warning
    237   self->_name = 0;
    238 
    239   doSomethingWithName(other->_name);
    240   [other.name release]; // no-warning
    241 }
    242 
    243 - (void)deliberateReleaseFalseNegative {
    244   // This is arguably a false negative because the result of p.friend shouldn't
    245   // be released, even though we are manipulating the ivar in between the two
    246   // actions.
    247   id name = self.name;
    248   _name = 0;
    249   [name release];
    250 }
    251 
    252 - (void)testRetainAndRelease {
    253   [self.name retain];
    254   [self.name release];
    255   [self.name release]; // expected-warning{{not owned}}
    256 }
    257 
    258 - (void)testRetainAndReleaseIVar {
    259   [self.name retain];
    260   [_name release];
    261   [_name release];
    262 }
    263 
    264 @end
    265 #endif
    266 
    267 @interface IntWrapper
    268 @property int value;
    269 @end
    270 
    271 @implementation IntWrapper
    272 @synthesize value;
    273 @end
    274 
    275 void testConsistencyInt(IntWrapper *w) {
    276   clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
    277 
    278   int origValue = w.value;
    279   if (origValue != 42)
    280     return;
    281 
    282   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    283 }
    284 
    285 void testConsistencyInt2(IntWrapper *w) {
    286   if (w.value != 42)
    287     return;
    288 
    289   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    290 }
    291 
    292 
    293 @interface IntWrapperAuto
    294 @property int value;
    295 @end
    296 
    297 @implementation IntWrapperAuto
    298 @end
    299 
    300 void testConsistencyIntAuto(IntWrapperAuto *w) {
    301   clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
    302 
    303   int origValue = w.value;
    304   if (origValue != 42)
    305     return;
    306 
    307   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    308 }
    309 
    310 void testConsistencyIntAuto2(IntWrapperAuto *w) {
    311   if (w.value != 42)
    312     return;
    313 
    314   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    315 }
    316 
    317 
    318 typedef struct {
    319   int value;
    320 } IntWrapperStruct;
    321 
    322 @interface StructWrapper
    323 @property IntWrapperStruct inner;
    324 @end
    325 
    326 @implementation StructWrapper
    327 @synthesize inner;
    328 @end
    329 
    330 void testConsistencyStruct(StructWrapper *w) {
    331   clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
    332 
    333   int origValue = w.inner.value;
    334   if (origValue != 42)
    335     return;
    336 
    337   clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
    338 }
    339 
    340 
    341 @interface OpaqueIntWrapper
    342 @property int value;
    343 @end
    344 
    345 // For now, don't assume a property is implemented using an ivar unless we can
    346 // actually see that it is.
    347 void testOpaqueConsistency(OpaqueIntWrapper *w) {
    348   clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
    349 }
    350 
    351 
    352 #if !__has_feature(objc_arc)
    353 // Test quite a few cases of retain/release issues.
    354 
    355 @interface RetainCountTesting
    356 @property (strong) id ownedProp;
    357 @property (unsafe_unretained) id unownedProp;
    358 @property (nonatomic, strong) id manualProp;
    359 @property (readonly) id readonlyProp;
    360 @property (nonatomic, readwrite/*, assign */) id implicitManualProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
    361 @property (nonatomic, readwrite/*, assign */) id implicitSynthProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
    362 @property CFTypeRef cfProp;
    363 @end
    364 
    365 @implementation RetainCountTesting {
    366   id _ivarOnly;
    367 }
    368 
    369 - (id)manualProp {
    370   return _manualProp;
    371 }
    372 
    373 - (void)setImplicitManualProp:(id)newValue {}
    374 
    375 - (void)testOverreleaseOwnedIvar {
    376   [_ownedProp retain];
    377   [_ownedProp release];
    378   [_ownedProp release];
    379   [_ownedProp release]; // FIXME-warning{{used after it is released}}
    380 }
    381 
    382 - (void)testOverreleaseUnownedIvar {
    383   [_unownedProp retain];
    384   [_unownedProp release];
    385   [_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}}
    386 }
    387 
    388 - (void)testOverreleaseIvarOnly {
    389   [_ivarOnly retain];
    390   [_ivarOnly release];
    391   [_ivarOnly release];
    392   [_ivarOnly release]; // FIXME-warning{{used after it is released}}
    393 }
    394 
    395 - (void)testOverreleaseReadonlyIvar {
    396   [_readonlyProp retain];
    397   [_readonlyProp release];
    398   [_readonlyProp release];
    399   [_readonlyProp release]; // FIXME-warning{{used after it is released}}
    400 }
    401 
    402 - (void)testOverreleaseImplicitManualIvar {
    403   [_implicitManualProp retain];
    404   [_implicitManualProp release];
    405   [_implicitManualProp release];
    406   [_implicitManualProp release]; // FIXME-warning{{used after it is released}}
    407 }
    408 
    409 - (void)testOverreleaseImplicitSynthIvar {
    410   [_implicitSynthProp retain];
    411   [_implicitSynthProp release];
    412   [_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}}
    413 }
    414 
    415 - (void)testOverreleaseCF {
    416   CFRetain(_cfProp);
    417   CFRelease(_cfProp);
    418   CFRelease(_cfProp);
    419   CFRelease(_cfProp); // FIXME-warning{{used after it is released}}
    420 }
    421 
    422 - (void)testOverreleaseOwnedIvarUse {
    423   [_ownedProp retain];
    424   [_ownedProp release];
    425   [_ownedProp release];
    426   [_ownedProp myMethod]; // FIXME-warning{{used after it is released}}
    427 }
    428 
    429 - (void)testOverreleaseIvarOnlyUse {
    430   [_ivarOnly retain];
    431   [_ivarOnly release];
    432   [_ivarOnly release];
    433   [_ivarOnly myMethod]; // FIXME-warning{{used after it is released}}
    434 }
    435 
    436 - (void)testOverreleaseCFUse {
    437   CFRetain(_cfProp);
    438   CFRelease(_cfProp);
    439   CFRelease(_cfProp);
    440 
    441   extern void CFUse(CFTypeRef);
    442   CFUse(_cfProp); // FIXME-warning{{used after it is released}}
    443 }
    444 
    445 - (void)testOverreleaseOwnedIvarAutoreleaseOkay {
    446   [_ownedProp retain];
    447   [_ownedProp release];
    448   [_ownedProp autorelease];
    449 } // no-warning
    450 
    451 - (void)testOverreleaseIvarOnlyAutoreleaseOkay {
    452   [_ivarOnly retain];
    453   [_ivarOnly release];
    454   [_ivarOnly autorelease];
    455 } // no-warning
    456 
    457 - (void)testOverreleaseOwnedIvarAutorelease {
    458   [_ownedProp retain];
    459   [_ownedProp release];
    460   [_ownedProp autorelease];
    461   [_ownedProp autorelease];
    462 } // FIXME-warning{{Object autoreleased too many times}}
    463 
    464 - (void)testOverreleaseIvarOnlyAutorelease {
    465   [_ivarOnly retain];
    466   [_ivarOnly release];
    467   [_ivarOnly autorelease];
    468   [_ivarOnly autorelease];
    469 } // FIXME-warning{{Object autoreleased too many times}}
    470 
    471 - (void)testPropertyAccessThenReleaseOwned {
    472   id owned = [self.ownedProp retain];
    473   [owned release];
    474   [_ownedProp release];
    475   clang_analyzer_eval(owned == _ownedProp); // expected-warning{{TRUE}}
    476 }
    477 
    478 - (void)testPropertyAccessThenReleaseOwned2 {
    479   id fromIvar = _ownedProp;
    480   id owned = [self.ownedProp retain];
    481   [owned release];
    482   [fromIvar release];
    483   clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
    484 }
    485 
    486 - (void)testPropertyAccessThenReleaseUnowned {
    487   id unowned = [self.unownedProp retain];
    488   [unowned release];
    489   [_unownedProp release]; // FIXME-warning{{not owned}}
    490 }
    491 
    492 - (void)testPropertyAccessThenReleaseUnowned2 {
    493   id fromIvar = _unownedProp;
    494   id unowned = [self.unownedProp retain];
    495   [unowned release];
    496   clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}}
    497   [fromIvar release]; // FIXME-warning{{not owned}}
    498 }
    499 
    500 - (void)testPropertyAccessThenReleaseManual {
    501   id prop = [self.manualProp retain];
    502   [prop release];
    503   [_manualProp release]; // no-warning
    504 }
    505 
    506 - (void)testPropertyAccessThenReleaseManual2 {
    507   id fromIvar = _manualProp;
    508   id prop = [self.manualProp retain];
    509   [prop release];
    510   clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
    511   [fromIvar release]; // no-warning
    512 }
    513 
    514 - (void)testPropertyAccessThenReleaseCF {
    515   CFTypeRef owned = CFRetain(self.cfProp);
    516   CFRelease(owned);
    517   CFRelease(_cfProp); // no-warning
    518   clang_analyzer_eval(owned == _cfProp); // expected-warning{{TRUE}}
    519 }
    520 
    521 - (void)testPropertyAccessThenReleaseCF2 {
    522   CFTypeRef fromIvar = _cfProp;
    523   CFTypeRef owned = CFRetain(self.cfProp);
    524   CFRelease(owned);
    525   CFRelease(fromIvar);
    526   clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
    527 }
    528 
    529 - (void)testPropertyAccessThenReleaseReadonly {
    530   id prop = [self.readonlyProp retain];
    531   [prop release];
    532   [_readonlyProp release]; // no-warning
    533 }
    534 
    535 - (void)testPropertyAccessThenReleaseReadonly2 {
    536   id fromIvar = _readonlyProp;
    537   id prop = [self.readonlyProp retain];
    538   [prop release];
    539   clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
    540   [fromIvar release]; // no-warning
    541 }
    542 
    543 - (void)testPropertyAccessThenReleaseImplicitManual {
    544   id prop = [self.implicitManualProp retain];
    545   [prop release];
    546   [_implicitManualProp release]; // no-warning
    547 }
    548 
    549 - (void)testPropertyAccessThenReleaseImplicitManual2 {
    550   id fromIvar = _implicitManualProp;
    551   id prop = [self.implicitManualProp retain];
    552   [prop release];
    553   clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
    554   [fromIvar release]; // no-warning
    555 }
    556 
    557 - (void)testPropertyAccessThenReleaseImplicitSynth {
    558   id prop = [self.implicitSynthProp retain];
    559   [prop release];
    560   [_implicitSynthProp release]; // FIXME-warning{{not owned}}
    561 }
    562 
    563 - (void)testPropertyAccessThenReleaseImplicitSynth2 {
    564   id fromIvar = _implicitSynthProp;
    565   id prop = [self.implicitSynthProp retain];
    566   [prop release];
    567   clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
    568   [fromIvar release]; // FIXME-warning{{not owned}}
    569 }
    570 
    571 - (id)getUnownedFromProperty {
    572   [_ownedProp retain];
    573   [_ownedProp autorelease];
    574   return _ownedProp; // no-warning
    575 }
    576 
    577 - (id)transferUnownedFromProperty {
    578   [_ownedProp retain];
    579   [_ownedProp autorelease];
    580   return [_ownedProp autorelease]; // no-warning
    581 }
    582 
    583 - (id)transferOwnedFromProperty __attribute__((ns_returns_retained)) {
    584   [_ownedProp retain];
    585   [_ownedProp autorelease];
    586   return _ownedProp; // no-warning
    587 }
    588 
    589 - (void)testAssignOwned:(id)newValue {
    590   _ownedProp = newValue;
    591   [_ownedProp release]; // FIXME: no-warning{{not owned}}
    592 }
    593 
    594 - (void)testAssignUnowned:(id)newValue {
    595   _unownedProp = newValue;
    596   [_unownedProp release]; // FIXME: no-warning{{not owned}}
    597 }
    598 
    599 - (void)testAssignIvarOnly:(id)newValue {
    600   _ivarOnly = newValue;
    601   [_ivarOnly release]; // FIXME: no-warning{{not owned}}
    602 }
    603 
    604 - (void)testAssignCF:(CFTypeRef)newValue {
    605   _cfProp = newValue;
    606   CFRelease(_cfProp); // FIXME: no-warning{{not owned}}
    607 }
    608 
    609 - (void)testAssignReadonly:(id)newValue {
    610   _readonlyProp = newValue;
    611   [_readonlyProp release]; // FIXME: no-warning{{not owned}}
    612 }
    613 
    614 - (void)testAssignImplicitManual:(id)newValue {
    615   _implicitManualProp = newValue;
    616   [_implicitManualProp release]; // FIXME: no-warning{{not owned}}
    617 }
    618 
    619 - (void)testAssignImplicitSynth:(id)newValue {
    620   _implicitSynthProp = newValue;
    621   [_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
    622 }
    623 
    624 - (void)testAssignOwnedOkay:(id)newValue {
    625   _ownedProp = [newValue retain];
    626   [_ownedProp release]; // no-warning
    627 }
    628 
    629 - (void)testAssignUnownedOkay:(id)newValue {
    630   _unownedProp = [newValue retain];
    631   [_unownedProp release]; // no-warning
    632 }
    633 
    634 - (void)testAssignIvarOnlyOkay:(id)newValue {
    635   _ivarOnly = [newValue retain];
    636   [_ivarOnly release]; // no-warning
    637 }
    638 
    639 - (void)testAssignCFOkay:(CFTypeRef)newValue {
    640   _cfProp = CFRetain(newValue);
    641   CFRelease(_cfProp); // no-warning
    642 }
    643 
    644 - (void)testAssignReadonlyOkay:(id)newValue {
    645   _readonlyProp = [newValue retain];
    646   [_readonlyProp release]; // FIXME: no-warning{{not owned}}
    647 }
    648 
    649 - (void)testAssignImplicitManualOkay:(id)newValue {
    650   _implicitManualProp = [newValue retain];
    651   [_implicitManualProp release]; // FIXME: no-warning{{not owned}}
    652 }
    653 
    654 - (void)testAssignImplicitSynthOkay:(id)newValue {
    655   _implicitSynthProp = [newValue retain];
    656   [_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
    657 }
    658 
    659 // rdar://problem/19862648
    660 - (void)establishIvarIsNilDuringLoops {
    661   extern id getRandomObject();
    662 
    663   int i = 4; // Must be at least 4 to trigger the bug.
    664   while (--i) {
    665     id x = 0;
    666     if (getRandomObject())
    667       x = _ivarOnly;
    668     if (!x)
    669       x = getRandomObject();
    670     [x myMethod];
    671   }
    672 }
    673 
    674 // rdar://problem/20335433
    675 - (void)retainIvarAndInvalidateSelf {
    676   extern void invalidate(id);
    677   [_unownedProp retain];
    678   invalidate(self);
    679   [_unownedProp release]; // no-warning
    680 }
    681 
    682 @end
    683 #endif // non-ARC
    684 
    685