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