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