1// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s 2// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-config mode=shallow -verify -Wno-objc-root-class %s 3// RUN: %clang_analyze_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s 4// RUN: %clang_analyze_cc1 -DOSATOMIC_USE_INLINED -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s 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 16typedef long long int64_t; 17_Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ); 18#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap64Barrier 19typedef int64_t intptr_t; 20#else 21typedef int int32_t; 22_Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue ); 23#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap32Barrier 24typedef int32_t intptr_t; 25#endif 26 27typedef const void * CFTypeRef; 28typedef const struct __CFString * CFStringRef; 29typedef const struct __CFAllocator * CFAllocatorRef; 30extern const CFAllocatorRef kCFAllocatorDefault; 31extern CFTypeRef CFRetain(CFTypeRef cf); 32void CFRelease(CFTypeRef cf); 33typedef const struct __CFDictionary * CFDictionaryRef; 34const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key); 35extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...); 36typedef signed char BOOL; 37typedef int NSInteger; 38typedef unsigned int NSUInteger; 39@class NSString, Protocol; 40extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); 41typedef NSInteger NSComparisonResult; 42typedef 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 63extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); 64typedef struct {} NSFastEnumerationState; 65@protocol NSFastEnumeration 66- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; 67@end 68@class NSString; 69typedef 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 77typedef unsigned short unichar; 78@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale; 79typedef 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 91extern void *_NSConstantStringClassReference; 92 93//===----------------------------------------------------------------------===// 94// Test cases. 95//===----------------------------------------------------------------------===// 96 97NSComparisonResult f1(NSString* s) { 98 NSString *aString = 0; 99 return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil}} 100} 101 102NSComparisonResult f2(NSString* s) { 103 NSString *aString = 0; 104 return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil}} 105} 106 107NSComparisonResult 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 112NSComparisonResult 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 117NSComparisonResult 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 122NSArray *f6(NSString* s) { 123 return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil}} 124} 125 126NSString* 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 137NSMutableArray* 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 146void 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 154NSString* 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). 163NSString* 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. 174void unknown_function_f12(NSString** s); 175void f12() { 176 NSString *string = [[NSString alloc] init]; 177 unknown_function_f12(&string); // no-warning 178} 179 180// Test double release of CFString (PR 4014). 181void 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 190void 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 278id testSharedClassFromFunction() { 279 return [[SharedClass alloc] _init]; // no-warning 280} 281 282#if !(defined(OSATOMIC_USE_INLINED) && OSATOMIC_USE_INLINED) 283// Test OSCompareAndSwap 284_Bool OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue ); 285extern BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation); 286#else 287// Test that the body farm models are still used even when a body is available. 288_Bool opaque_OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue ); 289_Bool OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue ) { 290 return opaque_OSAtomicCompareAndSwapPtr(__oldValue, __newValue, __theValue); 291} 292// Test that the analyzer doesn't crash when the farm model is used. 293// The analyzer ignores the autosynthesized code. 294_Bool OSAtomicCompareAndSwapEmptyFunction( void *__oldValue, void *__newValue, void * volatile *__theValue ) { 295 return 0; 296} 297extern BOOL opaque_objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation); 298extern BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) { 299 return opaque_objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); 300} 301#endif 302 303void testOSCompareAndSwap() { 304 NSString *old = 0; 305 NSString *s = [[NSString alloc] init]; // no-warning 306 if (!OSAtomicCompareAndSwapPtr(0, s, (void**) &old)) 307 [s release]; 308 else 309 [old release]; 310} 311 312void testOSCompareAndSwapXXBarrier_local() { 313 NSString *old = 0; 314 NSString *s = [[NSString alloc] init]; // no-warning 315 if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) 316 [s release]; 317 else 318 [old release]; 319} 320 321void testOSCompareAndSwapXXBarrier_local_no_direct_release() { 322 NSString *old = 0; 323 NSString *s = [[NSString alloc] init]; // no-warning 324 if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) 325 return; 326 else 327 [old release]; 328} 329 330int testOSCompareAndSwapXXBarrier_id(Class myclass, id xclass) { 331 if (COMPARE_SWAP_BARRIER(0, (intptr_t) myclass, (intptr_t*) &xclass)) 332 return 1; 333 return 0; 334} 335 336void test_objc_atomicCompareAndSwap_local() { 337 NSString *old = 0; 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 345void test_objc_atomicCompareAndSwap_local_no_direct_release() { 346 NSString *old = 0; 347 NSString *s = [[NSString alloc] init]; // no-warning 348 if (!objc_atomicCompareAndSwapPtr(0, s, &old)) 349 return; 350 else 351 [old release]; 352} 353 354void test_objc_atomicCompareAndSwap_parameter(NSString **old) { 355 NSString *s = [[NSString alloc] init]; // no-warning 356 if (!objc_atomicCompareAndSwapPtr(0, s, old)) 357 [s release]; 358 else 359 [*old release]; 360} 361 362void test_objc_atomicCompareAndSwap_parameter_no_direct_release(NSString **old) { 363 NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} 364 if (!objc_atomicCompareAndSwapPtr(0, s, old)) 365 return; 366 else 367 [*old release]; 368} 369 370 371// Test stringWithFormat (<rdar://problem/6815234>) 372void test_stringWithFormat() { 373 NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; 374 [string release]; 375 [string release]; // expected-warning{{Incorrect decrement of the reference count}} 376} 377 378// Test isTrackedObjectType(). 379typedef NSString* WonkyTypedef; 380@interface TestIsTracked 381+ (WonkyTypedef)newString; 382@end 383 384void test_isTrackedObjectType(void) { 385 NSString *str = [TestIsTracked newString]; // expected-warning{{Potential leak}} 386} 387 388// Test isTrackedCFObjectType(). 389@interface TestIsCFTracked 390+ (CFStringRef) badNewCFString; 391+ (CFStringRef) newCFString; 392@end 393 394@implementation TestIsCFTracked 395+ (CFStringRef) newCFString { 396 return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // no-warning 397} 398+ (CFStringRef) badNewCFString { 399 return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // expected-warning{{leak}} 400} 401 402// Test @synchronized 403void test_synchronized(id x) { 404 @synchronized(x) { 405 NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}} 406 } 407} 408@end 409 410void testOSCompareAndSwapXXBarrier_parameter(NSString **old) { 411 NSString *s = [[NSString alloc] init]; // no-warning 412 if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) 413 [s release]; 414 else 415 [*old release]; 416} 417 418void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) { 419 NSString *s = [[NSString alloc] init]; // no-warning 420 if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) 421 [s release]; 422 else 423 return; 424} 425 426@interface AlwaysInlineBodyFarmBodies : NSObject { 427 NSString *_value; 428} 429 - (NSString *)_value; 430 - (void)callValue; 431@end 432 433@implementation AlwaysInlineBodyFarmBodies 434 435- (NSString *)_value { 436 if (!_value) { 437 NSString *s = [[NSString alloc] init]; 438 if (!OSAtomicCompareAndSwapPtr(0, s, (void**)&_value)) { 439 [s release]; 440 } 441 } 442 return _value; 443} 444 445- (void)callValue { 446 [self _value]; 447} 448@end 449