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 signed char BOOL;
      7 typedef unsigned int NSUInteger;
      8 typedef struct _NSZone NSZone;
      9 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
     10 @protocol NSObject  - (BOOL)isEqual:(id)object; @end
     11 @protocol NSCopying  - (id)copyWithZone:(NSZone *)zone; @end
     12 @protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder; @end
     13 @protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone; @end
     14 @interface NSObject <NSObject> {}
     15 +(id)alloc;
     16 -(id)init;
     17 -(id)autorelease;
     18 -(id)copy;
     19 -(id)retain;
     20 -(oneway void)release;
     21 @end
     22 @interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
     23 - (NSUInteger)length;
     24 -(id)initWithFormat:(NSString *)f,...;
     25 -(BOOL)isEqualToString:(NSString *)s;
     26 + (id)string;
     27 @end
     28 @interface NSNumber : NSObject {}
     29 +(id)alloc;
     30 -(id)initWithInteger:(int)i;
     31 @end
     32 
     33 // rdar://6946338
     34 
     35 @interface Test1 : NSObject {
     36   NSString *text;
     37 }
     38 -(id)myMethod;
     39 @property (nonatomic, assign) NSString *text;
     40 @end
     41 
     42 
     43 #if !__has_feature(objc_arc)
     44 
     45 @implementation Test1
     46 
     47 @synthesize text;
     48 
     49 -(id)myMethod {
     50   Test1 *cell = [[[Test1 alloc] init] autorelease];
     51 
     52   NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
     53   cell.text = string1;
     54 
     55   return cell;
     56 }
     57 
     58 @end
     59 
     60 
     61 // rdar://8824416
     62 
     63 @interface MyNumber : NSObject
     64 {
     65   NSNumber* _myNumber;
     66 }
     67 
     68 - (id)initWithNumber:(NSNumber *)number;
     69 
     70 @property (nonatomic, readonly) NSNumber* myNumber;
     71 @property (nonatomic, readonly) NSNumber* newMyNumber;
     72 
     73 @end
     74 
     75 @implementation MyNumber
     76 @synthesize myNumber=_myNumber;
     77  
     78 - (id)initWithNumber:(NSNumber *)number
     79 {
     80   self = [super init];
     81   
     82   if ( self )
     83   {
     84     _myNumber = [number copy];
     85   }
     86   
     87   return self;
     88 }
     89 
     90 - (NSNumber*)newMyNumber
     91 {
     92   if ( _myNumber )
     93     return [_myNumber retain];
     94   
     95   return [[NSNumber alloc] initWithInteger:1];
     96 }
     97 
     98 - (id)valueForUndefinedKey:(NSString*)key
     99 {
    100   id value = 0;
    101   
    102   if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
    103     value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
    104   else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
    105     value = [self.myNumber retain]; // this line fixes the over release
    106   else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
    107     value = self.newMyNumber; // this one is ok, since value is returned retained
    108   else 
    109     value = [[NSNumber alloc] initWithInteger:0];
    110   
    111   return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
    112 }
    113 
    114 @end
    115 
    116 NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
    117 {
    118   NSNumber* result = aMyNumber.myNumber;
    119     
    120   return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
    121 }
    122 
    123 #endif
    124 
    125 
    126 // rdar://6611873
    127 
    128 @interface Person : NSObject {
    129   NSString *_name;
    130 }
    131 @property (retain) NSString * name;
    132 @property (assign) id friend;
    133 @end
    134 
    135 @implementation Person
    136 @synthesize name = _name;
    137 @end
    138 
    139 #if !__has_feature(objc_arc)
    140 void rdar6611873() {
    141   Person *p = [[[Person alloc] init] autorelease];
    142   
    143   p.name = [[NSString string] retain]; // expected-warning {{leak}}
    144   p.name = [[NSString alloc] init]; // expected-warning {{leak}}
    145 
    146   p.friend = [[Person alloc] init]; // expected-warning {{leak}}
    147 }
    148 #endif
    149 
    150 @interface SubPerson : Person
    151 -(NSString *)foo;
    152 @end
    153 
    154 @implementation SubPerson
    155 -(NSString *)foo {
    156   return super.name;
    157 }
    158 @end
    159 
    160 
    161 #if !__has_feature(objc_arc)
    162 // <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
    163 @interface RDar9241180
    164 @property (readwrite,assign) id x;
    165 -(id)testAnalyzer1:(int) y;
    166 -(void)testAnalyzer2;
    167 @end
    168 
    169 @implementation RDar9241180
    170 @synthesize x;
    171 -(id)testAnalyzer1:(int)y {
    172     RDar9241180 *o;
    173     if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
    174       return o;
    175     return o; // expected-warning {{Undefined or garbage value returned to caller}}
    176 }
    177 -(void)testAnalyzer2 {
    178   id y;
    179   self.x = y;  // expected-warning {{Argument for property setter is an uninitialized value}}
    180 }
    181 @end
    182 #endif
    183 
    184 
    185 //------
    186 // Property accessor synthesis
    187 //------
    188 
    189 extern void doSomethingWithPerson(Person *p);
    190 extern void doSomethingWithName(NSString *name);
    191 
    192 void testConsistencyRetain(Person *p) {
    193   clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
    194 
    195   id origName = p.name;
    196   clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
    197   doSomethingWithPerson(p);
    198   clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
    199 }
    200 
    201 void testConsistencyAssign(Person *p) {
    202   clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
    203 
    204   id origFriend = p.friend;
    205   clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
    206   doSomethingWithPerson(p);
    207   clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
    208 }
    209 
    210 #if !__has_feature(objc_arc)
    211 void testOverrelease(Person *p, int coin) {
    212   switch (coin) {
    213   case 0:
    214     [p.name release]; // expected-warning{{not owned}}
    215     break;
    216   case 1:
    217     [p.friend release]; // expected-warning{{not owned}}
    218     break;
    219   case 2: {
    220     id friend = p.friend;
    221     doSomethingWithPerson(p);
    222     [friend release]; // expected-warning{{not owned}}
    223   }
    224   }
    225 }
    226 
    227 // <rdar://problem/16333368>
    228 @implementation Person (Rdar16333368)
    229 
    230 - (void)testDeliberateRelease:(Person *)other {
    231   doSomethingWithName(self.name);
    232   [_name release]; // no-warning
    233   self->_name = 0;
    234 
    235   doSomethingWithName(other->_name);
    236   [other.name release]; // expected-warning{{not owned}}
    237 }
    238 
    239 - (void)deliberateReleaseFalseNegative {
    240   // This is arguably a false negative because the result of p.friend shouldn't
    241   // be released, even though we are manipulating the ivar in between the two
    242   // actions.
    243   id name = self.name;
    244   _name = 0;
    245   [name release];
    246 }
    247 
    248 - (void)testRetainAndRelease {
    249   [self.name retain];
    250   [self.name release];
    251   [self.name release]; // expected-warning{{not owned}}
    252 }
    253 
    254 - (void)testRetainAndReleaseIVar {
    255   [self.name retain];
    256   [_name release];
    257   [_name release]; // expected-warning{{not owned}}
    258 }
    259 
    260 @end
    261 #endif
    262 
    263 @interface IntWrapper
    264 @property int value;
    265 @end
    266 
    267 @implementation IntWrapper
    268 @synthesize value;
    269 @end
    270 
    271 void testConsistencyInt(IntWrapper *w) {
    272   clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
    273 
    274   int origValue = w.value;
    275   if (origValue != 42)
    276     return;
    277 
    278   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    279 }
    280 
    281 void testConsistencyInt2(IntWrapper *w) {
    282   if (w.value != 42)
    283     return;
    284 
    285   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    286 }
    287 
    288 
    289 @interface IntWrapperAuto
    290 @property int value;
    291 @end
    292 
    293 @implementation IntWrapperAuto
    294 @end
    295 
    296 void testConsistencyIntAuto(IntWrapperAuto *w) {
    297   clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
    298 
    299   int origValue = w.value;
    300   if (origValue != 42)
    301     return;
    302 
    303   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    304 }
    305 
    306 void testConsistencyIntAuto2(IntWrapperAuto *w) {
    307   if (w.value != 42)
    308     return;
    309 
    310   clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
    311 }
    312 
    313 
    314 typedef struct {
    315   int value;
    316 } IntWrapperStruct;
    317 
    318 @interface StructWrapper
    319 @property IntWrapperStruct inner;
    320 @end
    321 
    322 @implementation StructWrapper
    323 @synthesize inner;
    324 @end
    325 
    326 void testConsistencyStruct(StructWrapper *w) {
    327   clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
    328 
    329   int origValue = w.inner.value;
    330   if (origValue != 42)
    331     return;
    332 
    333   clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
    334 }
    335 
    336 
    337 @interface OpaqueIntWrapper
    338 @property int value;
    339 @end
    340 
    341 // For now, don't assume a property is implemented using an ivar unless we can
    342 // actually see that it is.
    343 void testOpaqueConsistency(OpaqueIntWrapper *w) {
    344   clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
    345 }
    346 
    347