1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s 2#import "Inputs/system-header-simulator-objc.h" 3#import "Inputs/system-header-simulator-for-malloc.h" 4 5// Done with headers. Start testing. 6void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) { 7 unsigned char *data = (unsigned char *)malloc(42); 8 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength]; 9} 10 11void testNSDataFreeWhenDoneYES(NSUInteger dataLength) { 12 unsigned char *data = (unsigned char *)malloc(42); 13 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 14} 15 16void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) { 17 unsigned char *data = (unsigned char *)malloc(42); 18 NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 19} 20 21void testNSDataFreeWhenDoneYES2_with_wrapper(NSUInteger dataLength) { 22 unsigned char *data = (unsigned char *)malloc(42); 23 Wrapper *nsdata = [[Wrapper alloc] initWithBytesNoCopy:data length:dataLength]; // no-warning 24} 25 26void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) { 27 unsigned char *data = (unsigned char *)malloc(42); 28 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; 29} 30 31void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) { 32 unichar *data = (unichar*)malloc(42); 33 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; 34 free(data); //expected-warning {{Attempt to free non-owned memory}} 35} 36 37void testNSStringFreeWhenDoneYES(NSUInteger dataLength) { 38 unsigned char *data = (unsigned char *)malloc(42); 39 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning 40} 41 42void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) { 43 unichar *data = (unichar*)malloc(42); 44 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 45} 46 47 48void testNSDataFreeWhenDoneNO(NSUInteger dataLength) { 49 unsigned char *data = (unsigned char *)malloc(42); 50 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 51} 52 53void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) { 54 unsigned char *data = (unsigned char *)malloc(42); 55 NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 56} 57 58 59void testNSStringFreeWhenDoneNO(NSUInteger dataLength) { 60 unsigned char *data = (unsigned char *)malloc(42); 61 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}} 62} 63 64void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) { 65 unichar *data = (unichar*)malloc(42); 66 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 67} 68 69void testOffsetFree() { 70 int *p = (int *)malloc(sizeof(int)); 71 NSData *nsdata = [NSData dataWithBytesNoCopy:++p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Argument to +dataWithBytesNoCopy:length:freeWhenDone: is offset by 4 bytes from the start of memory allocated by malloc()}} 72} 73 74void testRelinquished1() { 75 void *data = malloc(42); 76 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1]; 77 free(data); // expected-warning {{Attempt to free non-owned memory}} 78} 79 80void testRelinquished2() { 81 void *data = malloc(42); 82 NSData *nsdata; 83 free(data); 84 [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Use of memory after it is freed}} 85} 86 87@interface My 88+ (void)param:(void *)p; 89@end 90 91void testUseAfterFree() { 92 int *p = (int *)malloc(sizeof(int)); 93 free(p); 94 [My param:p]; // expected-warning{{Use of memory after it is freed}} 95} 96 97void testNoCopy() { 98 char *p = (char *)calloc(sizeof(int), 1); 99 CustomData *w = [CustomData somethingNoCopy:p]; // no-warning 100} 101 102void testFreeWhenDone() { 103 char *p = (char *)calloc(sizeof(int), 1); 104 CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning 105} 106 107void testFreeWhenDonePositive() { 108 char *p = (char *)calloc(sizeof(int), 1); 109 CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}} 110} 111 112void testFreeWhenDoneNoCopy() { 113 int *p = (int *)malloc(sizeof(int)); 114 CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning 115} 116 117void testFreeWhenDoneNoCopyPositive() { 118 int *p = (int *)malloc(sizeof(int)); 119 CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}} 120} 121 122// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided. 123void testNSDatafFreeWhenDone(NSUInteger dataLength) { 124 CFStringRef str; 125 char *bytes = (char*)malloc(12); 126 str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning 127 CFRelease(str); // default allocator also frees bytes 128} 129 130void stringWithExternalContentsExample(void) { 131#define BufferSize 1000 132 CFMutableStringRef mutStr; 133 UniChar *myBuffer; 134 135 myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar)); 136 137 mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}} 138 139 CFRelease(mutStr); 140 //free(myBuffer); 141} 142 143// PR12101 : pointers can escape through custom deallocators set on creation of a container. 144void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) { 145 void *key = malloc(12); 146 void *val = malloc(12); 147 CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks); 148 CFDictionarySetValue(x, key, val); 149 return;// no-warning 150} 151 152NSData *radar10976702() { 153 void *bytes = malloc(10); 154 return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning 155} 156 157void testBlocks() { 158 int *x= (int*)malloc(sizeof(int)); 159 int (^myBlock)(int) = ^(int num) { 160 free(x); 161 return num; 162 }; 163 myBlock(3); 164} 165 166// Test NSMapInsert. 167@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> 168@end 169extern void *NSMapGet(NSMapTable *table, const void *key); 170extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); 171extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); 172char *strdup(const char *s); 173 174NSString * radar11152419(NSString *string1, NSMapTable *map) { 175 const char *strkey = "key"; 176 NSString *string = ( NSString *)NSMapGet(map, strkey); 177 if (!string) { 178 string = [string1 copy]; 179 NSMapInsert(map, strdup(strkey), (void*)string); // no warning 180 NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning 181 } 182 return string; 183} 184 185// Test that we handle pointer escaping through OSAtomicEnqueue. 186typedef volatile struct { 187 void *opaque1; 188 long opaque2; 189} OSQueueHead; 190void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import)); 191static inline void radar11111210(OSQueueHead *pool) { 192 void *newItem = malloc(4); 193 OSAtomicEnqueue(pool, newItem, 4); 194} 195 196// Pointer might escape through CGDataProviderCreateWithData (radar://11187558). 197typedef struct CGDataProvider *CGDataProviderRef; 198typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, 199 size_t size); 200extern CGDataProviderRef CGDataProviderCreateWithData(void *info, 201 const void *data, size_t size, 202 CGDataProviderReleaseDataCallback releaseData) 203 __attribute__((visibility("default"))); 204void *calloc(size_t, size_t); 205 206static void releaseDataCallback (void *info, const void *data, size_t size) { 207#pragma unused (info, size) 208 free((void*)data); 209} 210void testCGDataProviderCreateWithData() { 211 void* b = calloc(8, 8); 212 CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback); 213} 214 215// Assume that functions which take a function pointer can free memory even if 216// they are defined in system headers and take the const pointer to the 217// allocated memory. (radar://11160612) 218extern CGDataProviderRef UnknownFunWithCallback(void *info, 219 const void *data, size_t size, 220 CGDataProviderReleaseDataCallback releaseData) 221 __attribute__((visibility("default"))); 222void testUnknownFunWithCallBack() { 223 void* b = calloc(8, 8); 224 CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback); 225} 226 227// Test blocks. 228void acceptBlockParam(void *, void (^block)(void *), unsigned); 229void testCallWithBlockCallback() { 230 void *l = malloc(12); 231 acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 232} 233 234// Test blocks in system headers. 235void testCallWithBlockCallbackInSystem() { 236 void *l = malloc(12); 237 SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 238} 239 240// Test escape into NSPointerArray. radar://11691035, PR13140 241void foo(NSPointerArray* pointerArray) { 242 243 void* p1 = malloc (1024); 244 if (p1) { 245 [pointerArray addPointer:p1]; 246 } 247 248 void* p2 = malloc (1024); 249 if (p2) { 250 [pointerArray insertPointer:p2 atIndex:1]; 251 } 252 253 void* p3 = malloc (1024); 254 if (p3) { 255 [pointerArray replacePointerAtIndex:1 withPointer:p3]; 256 } 257 258 // Freeing the buffer is allowed. 259 void* buffer = [pointerArray pointerAtIndex:0]; 260 free(buffer); 261} 262 263void noCrashOnVariableArgumentSelector() { 264 NSMutableString *myString = [NSMutableString stringWithString:@"some text"]; 265 [myString appendFormat:@"some text = %d", 3]; 266} 267 268void test12365078_check() { 269 unichar *characters = (unichar*)malloc(12); 270 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 271 if (!string) free(characters); // no-warning 272} 273 274void test12365078_nocheck() { 275 unichar *characters = (unichar*)malloc(12); 276 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 277} 278 279void test12365078_false_negative() { 280 unichar *characters = (unichar*)malloc(12); 281 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 282 if (!string) {;} 283} 284 285void test12365078_no_malloc(unichar *characters) { 286 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 287 if (!string) {free(characters);} 288} 289 290NSString *test12365078_no_malloc_returnValue(unichar *characters) { 291 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 292 if (!string) { 293 return 0; // no-warning 294 } 295 return string; 296} 297 298void test12365078_nocheck_nomalloc(unichar *characters) { 299 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 300 free(characters); // expected-warning {{Attempt to free non-owned memory}} 301} 302 303void test12365078_nested(unichar *characters) { 304 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 305 if (!string) { 306 NSString *string2 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 307 if (!string2) { 308 NSString *string3 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 309 if (!string3) { 310 NSString *string4 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 311 if (!string4) 312 free(characters); 313 } 314 } 315 } 316} 317 318void test12365078_check_positive() { 319 unichar *characters = (unichar*)malloc(12); 320 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 321 if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}} 322} 323