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