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