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