Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
      2 // RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
      3 
      4 
      5 //===----------------------------------------------------------------------===//
      6 // The following code is reduced using delta-debugging from
      7 // Foundation.h (Mac OS X).
      8 //
      9 // It includes the basic definitions for the test cases below.
     10 // Not directly including Foundation.h directly makes this test case 
     11 // both svelte and portable to non-Mac platforms.
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifdef TEST_64
     15 typedef long long int64_t;
     16 _Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue );
     17 #define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap64Barrier
     18 typedef int64_t intptr_t;
     19 #else
     20 typedef int int32_t;
     21 _Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue );
     22 #define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap32Barrier
     23 typedef int32_t intptr_t;
     24 #endif
     25 
     26 typedef const void * CFTypeRef;
     27 typedef const struct __CFString * CFStringRef;
     28 typedef const struct __CFAllocator * CFAllocatorRef;
     29 extern const CFAllocatorRef kCFAllocatorDefault;
     30 extern CFTypeRef CFRetain(CFTypeRef cf);
     31 void CFRelease(CFTypeRef cf);
     32 typedef const struct __CFDictionary * CFDictionaryRef;
     33 const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key);
     34 extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...);
     35 typedef signed char BOOL;
     36 typedef int NSInteger;
     37 typedef unsigned int NSUInteger;
     38 @class NSString, Protocol;
     39 extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
     40 typedef NSInteger NSComparisonResult;
     41 typedef struct _NSZone NSZone;
     42 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
     43 @protocol NSObject
     44 - (BOOL)isEqual:(id)object;
     45 - (oneway void)release;
     46 - (id)retain;
     47 - (id)autorelease;
     48 @end
     49 @protocol NSCopying
     50 - (id)copyWithZone:(NSZone *)zone;
     51 @end
     52 @protocol NSMutableCopying
     53 - (id)mutableCopyWithZone:(NSZone *)zone;
     54 @end
     55 @protocol NSCoding
     56 - (void)encodeWithCoder:(NSCoder *)aCoder;
     57 @end
     58 @interface NSObject <NSObject> {}
     59 - (id)init;
     60 + (id)alloc;
     61 @end
     62 extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
     63 typedef struct {} NSFastEnumerationState;
     64 @protocol NSFastEnumeration
     65 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
     66 @end
     67 @class NSString;
     68 typedef struct _NSRange {} NSRange;
     69 @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
     70 - (NSUInteger)count;
     71 @end
     72 @interface NSMutableArray : NSArray
     73 - (void)addObject:(id)anObject;
     74 - (id)initWithCapacity:(NSUInteger)numItems;
     75 @end
     76 typedef unsigned short unichar;
     77 @class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale;
     78 typedef NSUInteger NSStringCompareOptions;
     79 @interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>    - (NSUInteger)length;
     80 - (NSComparisonResult)compare:(NSString *)string;
     81 - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
     82 - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange;
     83 - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale;
     84 - (NSComparisonResult)caseInsensitiveCompare:(NSString *)string;
     85 - (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator;
     86 + (id)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
     87 @end
     88 @interface NSSimpleCString : NSString {} @end
     89 @interface NSConstantString : NSSimpleCString @end
     90 extern void *_NSConstantStringClassReference;
     91 
     92 //===----------------------------------------------------------------------===//
     93 // Test cases.
     94 //===----------------------------------------------------------------------===//
     95 
     96 NSComparisonResult f1(NSString* s) {
     97   NSString *aString = 0;
     98   return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil}}
     99 }
    100 
    101 NSComparisonResult f2(NSString* s) {
    102   NSString *aString = 0;
    103   return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil}}
    104 }
    105 
    106 NSComparisonResult f3(NSString* s, NSStringCompareOptions op) {
    107   NSString *aString = 0;
    108   return [s compare:aString options:op]; // expected-warning {{Argument to 'NSString' method 'compare:options:' cannot be nil}}
    109 }
    110 
    111 NSComparisonResult f4(NSString* s, NSStringCompareOptions op, NSRange R) {
    112   NSString *aString = 0;
    113   return [s compare:aString options:op range:R]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:' cannot be nil}}
    114 }
    115 
    116 NSComparisonResult f5(NSString* s, NSStringCompareOptions op, NSRange R) {
    117   NSString *aString = 0;
    118   return [s compare:aString options:op range:R locale:0]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:locale:' cannot be nil}}
    119 }
    120 
    121 NSArray *f6(NSString* s) {
    122   return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil}}
    123 }
    124 
    125 NSString* f7(NSString* s1, NSString* s2, NSString* s3) {
    126 
    127   NSString* s4 = (NSString*)
    128     CFStringCreateWithFormat(kCFAllocatorDefault, 0,  // expected-warning{{leak}}
    129                              (CFStringRef) __builtin___CFStringMakeConstantString("%@ %@ (%@)"), 
    130                              s1, s2, s3);
    131 
    132   CFRetain(s4);
    133   return s4;
    134 }
    135 
    136 NSMutableArray* f8() {
    137   
    138   NSString* s = [[NSString alloc] init];
    139   NSMutableArray* a = [[NSMutableArray alloc] initWithCapacity:2];
    140   [a addObject:s];
    141   [s release]; // no-warning
    142   return a;
    143 }
    144 
    145 void f9() {
    146   
    147   NSString* s = [[NSString alloc] init];
    148   NSString* q = s;
    149   [s release];
    150   [q release]; // expected-warning {{used after it is released}}
    151 }
    152 
    153 NSString* f10() {
    154   static NSString* s = 0;
    155   if (!s) s = [[NSString alloc] init];
    156   return s; // no-warning
    157 }
    158 
    159 // Test case for regression reported in <rdar://problem/6452745>.
    160 // Essentially 's' should not be considered allocated on the false branch.
    161 // This exercises the 'EvalAssume' logic in GRTransferFuncs (CFRefCount.cpp).
    162 NSString* f11(CFDictionaryRef dict, const char* key) {
    163   NSString* s = (NSString*) CFDictionaryGetValue(dict, key);
    164   [s retain];
    165   if (s) {
    166     [s release];
    167   }
    168   return 0;
    169 }
    170 
    171 // Test case for passing a tracked object by-reference to a function we
    172 // don't understand.
    173 void unknown_function_f12(NSString** s);
    174 void f12() {
    175   NSString *string = [[NSString alloc] init];
    176   unknown_function_f12(&string); // no-warning
    177 }
    178 
    179 // Test double release of CFString (PR 4014).
    180 void f13(void) {
    181   CFStringRef ref = CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100);
    182   CFRelease(ref);
    183   CFRelease(ref); // expected-warning{{Reference-counted object is used after it is released}}
    184 }
    185 
    186 @interface MyString : NSString
    187 @end
    188 
    189 void f14(MyString *s) {
    190   [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil}}
    191 }
    192 
    193 // Test regular use of -autorelease
    194 @interface TestAutorelease
    195 -(NSString*) getString;
    196 @end
    197 @implementation TestAutorelease
    198 -(NSString*) getString {
    199   NSString *str = [[NSString alloc] init];
    200   return [str autorelease]; // no-warning
    201 }
    202 - (void)m1
    203 {
    204  NSString *s = [[NSString alloc] init]; // expected-warning{{leak}}
    205  [s retain];
    206  [s autorelease];
    207 }
    208 - (void)m2
    209 {
    210  NSString *s = [[[NSString alloc] init] autorelease]; // expected-warning{{leak}}
    211  [s retain];
    212 }
    213 - (void)m3
    214 {
    215  NSString *s = [[[NSString alloc] init] autorelease];
    216  [s retain];
    217  [s autorelease];
    218 }
    219 - (void)m4
    220 {
    221  NSString *s = [[NSString alloc] init]; // expected-warning{{leak}}
    222  [s retain];
    223 }
    224 - (void)m5
    225 {
    226  NSString *s = [[NSString alloc] init];
    227  [s autorelease];
    228 }
    229 @end
    230 
    231 @interface C1 : NSObject {}
    232 - (NSString*) getShared;
    233 + (C1*) sharedInstance;
    234 @end
    235 @implementation C1 : NSObject {}
    236 - (NSString*) getShared {
    237   static NSString* s = 0;
    238   if (!s) s = [[NSString alloc] init];    
    239   return s; // no-warning  
    240 }
    241 + (C1 *)sharedInstance {
    242   static C1 *sharedInstance = 0;
    243   if (!sharedInstance) {
    244     sharedInstance = [[C1 alloc] init];
    245   }
    246   return sharedInstance; // no-warning
    247 }
    248 @end
    249 
    250 @interface SharedClass : NSObject
    251 + (id)sharedInstance;
    252 - (id)notShared;
    253 @end
    254 
    255 @implementation SharedClass
    256 
    257 - (id)_init {
    258     if ((self = [super init])) {
    259         NSLog(@"Bar");
    260     }
    261     return self;
    262 }
    263 
    264 - (id)notShared {
    265   return [[SharedClass alloc] _init]; // expected-warning{{leak}}
    266 }
    267 
    268 + (id)sharedInstance {
    269     static SharedClass *_sharedInstance = 0;
    270     if (!_sharedInstance) {
    271         _sharedInstance = [[SharedClass alloc] _init];
    272     }
    273     return _sharedInstance; // no-warning
    274 }
    275 @end
    276 
    277 id testSharedClassFromFunction() {
    278   return [[SharedClass alloc] _init]; // no-warning
    279 }
    280 
    281 // Test OSCompareAndSwap
    282 _Bool OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue );
    283 extern BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation);
    284 
    285 void testOSCompareAndSwap() {
    286   NSString *old = 0;
    287   NSString *s = [[NSString alloc] init]; // no-warning
    288   if (!OSAtomicCompareAndSwapPtr(0, s, (void**) &old))
    289     [s release];
    290   else    
    291     [old release];
    292 }
    293 
    294 void testOSCompareAndSwapXXBarrier_local() {
    295   NSString *old = 0;
    296   NSString *s = [[NSString alloc] init]; // no-warning
    297   if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old))
    298     [s release];
    299   else    
    300     [old release];
    301 }
    302 
    303 void testOSCompareAndSwapXXBarrier_local_no_direct_release() {
    304   NSString *old = 0;
    305   NSString *s = [[NSString alloc] init]; // no-warning
    306   if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old))
    307     return;
    308   else    
    309     [old release];
    310 }
    311 
    312 int testOSCompareAndSwapXXBarrier_id(Class myclass, id xclass) {
    313   if (COMPARE_SWAP_BARRIER(0, (intptr_t) myclass, (intptr_t*) &xclass))
    314     return 1;
    315   return 0;
    316 }
    317 
    318 void test_objc_atomicCompareAndSwap_local() {
    319   NSString *old = 0;
    320   NSString *s = [[NSString alloc] init]; // no-warning
    321   if (!objc_atomicCompareAndSwapPtr(0, s, &old))
    322     [s release];
    323   else    
    324     [old release];
    325 }
    326 
    327 void test_objc_atomicCompareAndSwap_local_no_direct_release() {
    328   NSString *old = 0;
    329   NSString *s = [[NSString alloc] init]; // no-warning
    330   if (!objc_atomicCompareAndSwapPtr(0, s, &old))
    331     return;
    332   else    
    333     [old release];
    334 }
    335 
    336 void test_objc_atomicCompareAndSwap_parameter(NSString **old) {
    337   NSString *s = [[NSString alloc] init]; // no-warning
    338   if (!objc_atomicCompareAndSwapPtr(0, s, old))
    339     [s release];
    340   else    
    341     [*old release];
    342 }
    343 
    344 void test_objc_atomicCompareAndSwap_parameter_no_direct_release(NSString **old) {
    345   NSString *s = [[NSString alloc] init]; // expected-warning{{leak}}
    346   if (!objc_atomicCompareAndSwapPtr(0, s, old))
    347     return;
    348   else    
    349     [*old release];
    350 }
    351 
    352 
    353 // Test stringWithFormat (<rdar://problem/6815234>)
    354 void test_stringWithFormat() {  
    355   NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain];
    356   [string release];
    357   [string release]; // expected-warning{{Incorrect decrement of the reference count}}
    358 }
    359 
    360 // Test isTrackedObjectType().
    361 typedef NSString* WonkyTypedef;
    362 @interface TestIsTracked
    363 + (WonkyTypedef)newString;
    364 @end
    365 
    366 void test_isTrackedObjectType(void) {
    367   NSString *str = [TestIsTracked newString]; // expected-warning{{Potential leak}}
    368 }
    369 
    370 // Test isTrackedCFObjectType().
    371 @interface TestIsCFTracked
    372 + (CFStringRef) badNewCFString;
    373 + (CFStringRef) newCFString;
    374 @end
    375 
    376 @implementation TestIsCFTracked
    377 + (CFStringRef) newCFString {
    378   return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // no-warning
    379 }
    380 + (CFStringRef) badNewCFString {
    381   return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // expected-warning{{leak}}
    382 }
    383 
    384 // Test @synchronized
    385 void test_synchronized(id x) {
    386   @synchronized(x) {
    387     NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}}
    388   }
    389 }
    390 @end
    391 
    392 void testOSCompareAndSwapXXBarrier_parameter(NSString **old) {
    393   NSString *s = [[NSString alloc] init]; // no-warning
    394   if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old))
    395     [s release];
    396   else    
    397     [*old release];
    398 }
    399 
    400 void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) {
    401   NSString *s = [[NSString alloc] init]; // no-warning
    402   if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old))
    403     [s release];
    404   else    
    405     return;
    406 }
    407