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