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