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 free() 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 {{Attempt to free released memory}} 85} 86 87void testNoCopy() { 88 char *p = (char *)calloc(sizeof(int), 1); 89 CustomData *w = [CustomData somethingNoCopy:p]; // no-warning 90} 91 92void testFreeWhenDone() { 93 char *p = (char *)calloc(sizeof(int), 1); 94 CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning 95} 96 97void testFreeWhenDonePositive() { 98 char *p = (char *)calloc(sizeof(int), 1); 99 CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}} 100} 101 102void testFreeWhenDoneNoCopy() { 103 int *p = (int *)malloc(sizeof(int)); 104 CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning 105} 106 107void testFreeWhenDoneNoCopyPositive() { 108 int *p = (int *)malloc(sizeof(int)); 109 CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}} 110} 111 112// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided. 113void testNSDatafFreeWhenDone(NSUInteger dataLength) { 114 CFStringRef str; 115 char *bytes = (char*)malloc(12); 116 str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning 117 CFRelease(str); // default allocator also frees bytes 118} 119 120void stringWithExternalContentsExample(void) { 121#define BufferSize 1000 122 CFMutableStringRef mutStr; 123 UniChar *myBuffer; 124 125 myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar)); 126 127 mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}} 128 129 CFRelease(mutStr); 130 //free(myBuffer); 131} 132 133// PR12101 : pointers can escape through custom deallocators set on creation of a container. 134void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) { 135 void *key = malloc(12); 136 void *val = malloc(12); 137 CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks); 138 CFDictionarySetValue(x, key, val); 139 return;// no-warning 140} 141 142NSData *radar10976702() { 143 void *bytes = malloc(10); 144 return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning 145} 146 147void testBlocks() { 148 int *x= (int*)malloc(sizeof(int)); 149 int (^myBlock)(int) = ^(int num) { 150 free(x); 151 return num; 152 }; 153 myBlock(3); 154} 155 156// Test NSMapInsert. 157@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> 158@end 159extern void *NSMapGet(NSMapTable *table, const void *key); 160extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); 161extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); 162char *strdup(const char *s); 163 164NSString * radar11152419(NSString *string1, NSMapTable *map) { 165 const char *strkey = "key"; 166 NSString *string = ( NSString *)NSMapGet(map, strkey); 167 if (!string) { 168 string = [string1 copy]; 169 NSMapInsert(map, strdup(strkey), (void*)string); // no warning 170 NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning 171 } 172 return string; 173} 174 175// Test that we handle pointer escaping through OSAtomicEnqueue. 176typedef volatile struct { 177 void *opaque1; 178 long opaque2; 179} OSQueueHead; 180void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import)); 181static inline void radar11111210(OSQueueHead *pool) { 182 void *newItem = malloc(4); 183 OSAtomicEnqueue(pool, newItem, 4); 184} 185 186// Pointer might escape through CGDataProviderCreateWithData (radar://11187558). 187typedef struct CGDataProvider *CGDataProviderRef; 188typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, 189 size_t size); 190extern CGDataProviderRef CGDataProviderCreateWithData(void *info, 191 const void *data, size_t size, 192 CGDataProviderReleaseDataCallback releaseData) 193 __attribute__((visibility("default"))); 194void *calloc(size_t, size_t); 195 196static void releaseDataCallback (void *info, const void *data, size_t size) { 197#pragma unused (info, size) 198 free((void*)data); 199} 200void testCGDataProviderCreateWithData() { 201 void* b = calloc(8, 8); 202 CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback); 203} 204 205// Assume that functions which take a function pointer can free memory even if 206// they are defined in system headers and take the const pointer to the 207// allocated memory. (radar://11160612) 208extern CGDataProviderRef UnknownFunWithCallback(void *info, 209 const void *data, size_t size, 210 CGDataProviderReleaseDataCallback releaseData) 211 __attribute__((visibility("default"))); 212void testUnknownFunWithCallBack() { 213 void* b = calloc(8, 8); 214 CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback); 215} 216 217// Test blocks. 218void acceptBlockParam(void *, void (^block)(void *), unsigned); 219void testCallWithBlockCallback() { 220 void *l = malloc(12); 221 acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 222} 223 224// Test blocks in system headers. 225void testCallWithBlockCallbackInSystem() { 226 void *l = malloc(12); 227 SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *)); 228} 229 230// Test escape into NSPointerArray. radar://11691035, PR13140 231void foo(NSPointerArray* pointerArray) { 232 233 void* p1 = malloc (1024); 234 if (p1) { 235 [pointerArray addPointer:p1]; 236 } 237 238 void* p2 = malloc (1024); 239 if (p2) { 240 [pointerArray insertPointer:p2 atIndex:1]; 241 } 242 243 void* p3 = malloc (1024); 244 if (p3) { 245 [pointerArray replacePointerAtIndex:1 withPointer:p3]; 246 } 247 248 // Freeing the buffer is allowed. 249 void* buffer = [pointerArray pointerAtIndex:0]; 250 free(buffer); 251} 252 253void noCrashOnVariableArgumentSelector() { 254 NSMutableString *myString = [NSMutableString stringWithString:@"some text"]; 255 [myString appendFormat:@"some text = %d", 3]; 256} 257 258void test12365078_check() { 259 unichar *characters = (unichar*)malloc(12); 260 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 261 if (!string) free(characters); // no-warning 262} 263 264void test12365078_nocheck() { 265 unichar *characters = (unichar*)malloc(12); 266 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 267} 268 269void test12365078_false_negative() { 270 unichar *characters = (unichar*)malloc(12); 271 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 272 if (!string) {;} 273} 274 275void test12365078_no_malloc(unichar *characters) { 276 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 277 if (!string) {free(characters);} 278} 279 280NSString *test12365078_no_malloc_returnValue(unichar *characters) { 281 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 282 if (!string) { 283 return 0; // no-warning 284 } 285 return string; 286} 287 288void test12365078_nocheck_nomalloc(unichar *characters) { 289 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 290 free(characters); // expected-warning {{Attempt to free non-owned memory}} 291} 292 293void test12365078_nested(unichar *characters) { 294 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 295 if (!string) { 296 NSString *string2 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 297 if (!string2) { 298 NSString *string3 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 299 if (!string3) { 300 NSString *string4 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 301 if (!string4) 302 free(characters); 303 } 304 } 305 } 306} 307 308void test12365078_check_positive() { 309 unichar *characters = (unichar*)malloc(12); 310 NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; 311 if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}} 312} 313