Home | History | Annotate | Download | only in Analysis
      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