// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s #import "Inputs/system-header-simulator-objc.h" #import "Inputs/system-header-simulator-for-malloc.h" // Done with headers. Start testing. void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength]; } void testNSDataFreeWhenDoneYES(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning } void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning } void testNSDataFreeWhenDoneYES2_with_wrapper(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); Wrapper *nsdata = [[Wrapper alloc] initWithBytesNoCopy:data length:dataLength]; // no-warning } void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; } void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) { unichar *data = (unichar*)malloc(42); NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; free(data); //expected-warning {{Attempt to free non-owned memory}} } void testNSStringFreeWhenDoneYES(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning } void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) { unichar *data = (unichar*)malloc(42); NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning } void testNSDataFreeWhenDoneNO(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} } void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} } void testNSStringFreeWhenDoneNO(NSUInteger dataLength) { unsigned char *data = (unsigned char *)malloc(42); NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}} } void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) { unichar *data = (unichar*)malloc(42); NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} } void testOffsetFree() { int *p = (int *)malloc(sizeof(int)); 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()}} } void testRelinquished1() { void *data = malloc(42); NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1]; free(data); // expected-warning {{Attempt to free non-owned memory}} } void testRelinquished2() { void *data = malloc(42); NSData *nsdata; free(data); [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Use of memory after it is freed}} } @interface My + (void)param:(void *)p; @end void testUseAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); [My param:p]; // expected-warning{{Use of memory after it is freed}} } void testNoCopy() { char *p = (char *)calloc(sizeof(int), 1); CustomData *w = [CustomData somethingNoCopy:p]; // no-warning } void testFreeWhenDone() { char *p = (char *)calloc(sizeof(int), 1); CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning } void testFreeWhenDonePositive() { char *p = (char *)calloc(sizeof(int), 1); CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}} } void testFreeWhenDoneNoCopy() { int *p = (int *)malloc(sizeof(int)); CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning } void testFreeWhenDoneNoCopyPositive() { int *p = (int *)malloc(sizeof(int)); CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}} } // Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided. void testNSDatafFreeWhenDone(NSUInteger dataLength) { CFStringRef str; char *bytes = (char*)malloc(12); str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning CFRelease(str); // default allocator also frees bytes } void stringWithExternalContentsExample(void) { #define BufferSize 1000 CFMutableStringRef mutStr; UniChar *myBuffer; myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar)); mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}} CFRelease(mutStr); //free(myBuffer); } // PR12101 : pointers can escape through custom deallocators set on creation of a container. void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) { void *key = malloc(12); void *val = malloc(12); CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(x, key, val); return;// no-warning } NSData *radar10976702() { void *bytes = malloc(10); return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning } void testBlocks() { int *x= (int*)malloc(sizeof(int)); int (^myBlock)(int) = ^(int num) { free(x); return num; }; myBlock(3); } // Test NSMapInsert. @interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> @end extern void *NSMapGet(NSMapTable *table, const void *key); extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); char *strdup(const char *s); NSString * radar11152419(NSString *string1, NSMapTable *map) { const char *strkey = "key"; NSString *string = ( NSString *)NSMapGet(map, strkey); if (!string) { string = [string1 copy]; NSMapInsert(map, strdup(strkey), (void*)string); // no warning NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning } return string; } // Test that we handle pointer escaping through OSAtomicEnqueue. typedef volatile struct { void *opaque1; long opaque2; } OSQueueHead; void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import)); static inline void radar11111210(OSQueueHead *pool) { void *newItem = malloc(4); OSAtomicEnqueue(pool, newItem, 4); } // Pointer might escape through CGDataProviderCreateWithData (radar://11187558). typedef struct CGDataProvider *CGDataProviderRef; typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, size_t size); extern CGDataProviderRef CGDataProviderCreateWithData(void *info, const void *data, size_t size, CGDataProviderReleaseDataCallback releaseData) __attribute__((visibility("default"))); void *calloc(size_t, size_t); static void releaseDataCallback (void *info, const void *data, size_t size) { #pragma unused (info, size) free((void*)data); } void testCGDataProviderCreateWithData() { void* b = calloc(8, 8); CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback); } // Assume that functions which take a function pointer can free memory even if // they are defined in system headers and take the const pointer to the // allocated memory. (radar://11160612) extern CGDataProviderRef UnknownFunWithCallback(void *info, const void *data, size_t size, CGDataProviderReleaseDataCallback releaseData) __attribute__((visibility("default"))); void testUnknownFunWithCallBack() { void* b = calloc(8, 8); CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback); } // Test blocks. void acceptBlockParam(void *, void (^block)(void *), unsigned); void testCallWithBlockCallback() { void *l = malloc(12); acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); } // Test blocks in system headers. void testCallWithBlockCallbackInSystem() { void *l = malloc(12); SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); } // Test escape into NSPointerArray. radar://11691035, PR13140 void foo(NSPointerArray* pointerArray) { void* p1 = malloc (1024); if (p1) { [pointerArray addPointer:p1]; } void* p2 = malloc (1024); if (p2) { [pointerArray insertPointer:p2 atIndex:1]; } void* p3 = malloc (1024); if (p3) { [pointerArray replacePointerAtIndex:1 withPointer:p3]; } // Freeing the buffer is allowed. void* buffer = [pointerArray pointerAtIndex:0]; free(buffer); } void noCrashOnVariableArgumentSelector() { NSMutableString *myString = [NSMutableString stringWithString:@"some text"]; [myString appendFormat:@"some text = %d", 3]; } void test12365078_check() { unichar *characters = (unichar*)malloc(12); NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string) free(characters); // no-warning } void test12365078_nocheck() { unichar *characters = (unichar*)malloc(12); NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; } void test12365078_false_negative() { unichar *characters = (unichar*)malloc(12); NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string) {;} } void test12365078_no_malloc(unichar *characters) { NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string) {free(characters);} } NSString *test12365078_no_malloc_returnValue(unichar *characters) { NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string) { return 0; // no-warning } return string; } void test12365078_nocheck_nomalloc(unichar *characters) { NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; free(characters); // expected-warning {{Attempt to free non-owned memory}} } void test12365078_nested(unichar *characters) { NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string) { NSString *string2 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string2) { NSString *string3 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string3) { NSString *string4 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (!string4) free(characters); } } } } void test12365078_check_positive() { unichar *characters = (unichar*)malloc(12); NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}} }