1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s 2#include "system-header-simulator-objc.h" 3 4typedef __typeof(sizeof(int)) size_t; 5void *malloc(size_t); 6void free(void *); 7 8// Done with headers. Start testing. 9void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) { 10 unsigned char *data = (unsigned char *)malloc(42); 11 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength]; 12} 13 14void testNSDataFreeWhenDoneYES(NSUInteger dataLength) { 15 unsigned char *data = (unsigned char *)malloc(42); 16 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 17} 18 19void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) { 20 unsigned char *data = (unsigned char *)malloc(42); 21 NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 22} 23 24void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) { 25 unsigned char *data = (unsigned char *)malloc(42); 26 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; 27} 28 29void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) { 30 unichar *data = (unichar*)malloc(42); 31 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; 32 free(data); //expected-warning {{Attempt to free non-owned memory}} 33} 34 35void testNSStringFreeWhenDoneYES(NSUInteger dataLength) { 36 unsigned char *data = (unsigned char *)malloc(42); 37 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning 38} 39 40void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) { 41 unichar *data = (unichar*)malloc(42); 42 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning 43} 44 45 46void testNSDataFreeWhenDoneNO(NSUInteger dataLength) { 47 unsigned char *data = (unsigned char *)malloc(42); 48 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 49} 50 51void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) { 52 unsigned char *data = (unsigned char *)malloc(42); 53 NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 54} 55 56 57void testNSStringFreeWhenDoneNO(NSUInteger dataLength) { 58 unsigned char *data = (unsigned char *)malloc(42); 59 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}} 60} 61 62void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) { 63 unichar *data = (unichar*)malloc(42); 64 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} 65} 66 67void testRelinquished1() { 68 void *data = malloc(42); 69 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1]; 70 free(data); // expected-warning {{Attempt to free non-owned memory}} 71} 72 73void testRelinquished2() { 74 void *data = malloc(42); 75 NSData *nsdata; 76 free(data); 77 [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Attempt to free released memory}} 78} 79 80// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided. 81void testNSDatafFreeWhenDone(NSUInteger dataLength) { 82 CFStringRef str; 83 char *bytes = (char*)malloc(12); 84 str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning 85 CFRelease(str); // default allocator also frees bytes 86} 87 88void stringWithExternalContentsExample(void) { 89#define BufferSize 1000 90 CFMutableStringRef mutStr; 91 UniChar *myBuffer; 92 93 myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar)); 94 95 mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}} 96 97 CFRelease(mutStr); 98 //free(myBuffer); 99} 100 101// PR12101 : pointers can escape through custom deallocators set on creation of a container. 102void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) { 103 void *key = malloc(12); 104 void *val = malloc(12); 105 CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks); 106 CFDictionarySetValue(x, key, val); 107 return;// no-warning 108} 109 110NSData *radar10976702() { 111 void *bytes = malloc(10); 112 return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning 113} 114 115void testBlocks() { 116 int *x= (int*)malloc(sizeof(int)); 117 int (^myBlock)(int) = ^(int num) { 118 free(x); 119 return num; 120 }; 121 myBlock(3); 122} 123 124// Test NSMapInsert. 125@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> 126@end 127extern void *NSMapGet(NSMapTable *table, const void *key); 128extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); 129extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); 130char *strdup(const char *s); 131 132NSString * radar11152419(NSString *string1, NSMapTable *map) { 133 const char *strkey = "key"; 134 NSString *string = ( NSString *)NSMapGet(map, strkey); 135 if (!string) { 136 string = [string1 copy]; 137 NSMapInsert(map, strdup(strkey), (void*)string); // no warning 138 NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning 139 } 140 return string; 141} 142 143// Test that we handle pointer escaping through OSAtomicEnqueue. 144typedef volatile struct { 145 void *opaque1; 146 long opaque2; 147} OSQueueHead; 148void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import)); 149static inline void radar11111210(OSQueueHead *pool) { 150 void *newItem = malloc(4); 151 OSAtomicEnqueue(pool, newItem, 4); 152} 153 154// Pointer might escape through CGDataProviderCreateWithData (radar://11187558). 155typedef struct CGDataProvider *CGDataProviderRef; 156typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, 157 size_t size); 158extern CGDataProviderRef CGDataProviderCreateWithData(void *info, 159 const void *data, size_t size, 160 CGDataProviderReleaseDataCallback releaseData) 161 __attribute__((visibility("default"))); 162void *calloc(size_t, size_t); 163 164static void releaseDataCallback (void *info, const void *data, size_t size) { 165#pragma unused (info, size) 166 free((void*)data); 167} 168void testCGDataProviderCreateWithData() { 169 void* b = calloc(8, 8); 170 CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback); 171} 172 173// Assume that functions which take a function pointer can free memory even if 174// they are defined in system headers and take the const pointer to the 175// allocated memory. (radar://11160612) 176extern CGDataProviderRef UnknownFunWithCallback(void *info, 177 const void *data, size_t size, 178 CGDataProviderReleaseDataCallback releaseData) 179 __attribute__((visibility("default"))); 180void testUnknownFunWithCallBack() { 181 void* b = calloc(8, 8); 182 CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback); 183} 184 185// Test blocks. 186void acceptBlockParam(void *, void (^block)(void *), unsigned); 187void testCallWithBlockCallback() { 188 void *l = malloc(12); 189 acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 190} 191 192// Test blocks in system headers. 193void testCallWithBlockCallbackInSystem() { 194 void *l = malloc(12); 195 SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 196} 197 198// Test escape into NSPointerArray. radar://11691035, PR13140 199void foo(NSPointerArray* pointerArray) { 200 201 void* p1 = malloc (1024); 202 if (p1) { 203 [pointerArray addPointer:p1]; 204 } 205 206 void* p2 = malloc (1024); 207 if (p2) { 208 [pointerArray insertPointer:p2 atIndex:1]; 209 } 210 211 void* p3 = malloc (1024); 212 if (p3) { 213 [pointerArray replacePointerAtIndex:1 withPointer:p3]; 214 } 215 216 // Freeing the buffer is allowed. 217 void* buffer = [pointerArray pointerAtIndex:0]; 218 free(buffer); 219} 220 221void noCrashOnVariableArgumentSelector() { 222 NSMutableString *myString = [NSMutableString stringWithString:@"some text"]; 223 [myString appendFormat:@"some text = %d", 3]; 224}