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