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