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