xref: /llvm-project/clang/test/Analysis/malloc.mm (revision 893a303962608469ec5bd01fe44e82c935152e9c)
1// RUN: %clang_analyze_cc1 -std=c++14 \
2// RUN:     -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete \
3// RUN:     -analyzer-checker=unix.MismatchedDeallocator \
4// RUN:     -verify -fblocks %s
5
6#import "Inputs/system-header-simulator-objc.h"
7#import "Inputs/system-header-simulator-for-malloc.h"
8
9// Done with headers. Start testing.
10void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) {
11  unsigned char *data = (unsigned char *)malloc(42);
12  NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength];
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
25void testNSDataFreeWhenDoneYES2_with_wrapper(NSUInteger dataLength) {
26  unsigned char *data = (unsigned char *)malloc(42);
27  Wrapper *nsdata = [[Wrapper alloc] initWithBytesNoCopy:data length:dataLength]; // no-warning
28}
29
30void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) {
31  unsigned char *data = (unsigned char *)malloc(42);
32  NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1];
33}
34
35void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) {
36  unichar *data = (unichar*)malloc(42);
37  NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1];
38  free(data); //expected-warning {{Attempt to free non-owned memory}}
39}
40
41void testNSStringFreeWhenDoneYES(NSUInteger dataLength) {
42  unsigned char *data = (unsigned char *)malloc(42);
43  NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning
44}
45
46void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) {
47  unichar *data = (unichar*)malloc(42);
48  NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
49}
50
51
52void testNSDataFreeWhenDoneNO(NSUInteger dataLength) {
53  unsigned char *data = (unsigned char *)malloc(42);
54  NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
55}
56
57void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) {
58  unsigned char *data = (unsigned char *)malloc(42);
59  NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
60}
61
62
63void testNSStringFreeWhenDoneNO(NSUInteger dataLength) {
64  unsigned char *data = (unsigned char *)malloc(42);
65  NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}}
66}
67
68void testNSStringFreeWhenDoneNewDelete(NSUInteger dataLength) {
69  unsigned char *data = new unsigned char(42);
70  NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data
71                                   length:dataLength freeWhenDone:1];
72  // expected-warning@-2{{-initWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'}}
73}
74
75void testNSStringFreeWhenDoneNewDelete2(NSUInteger dataLength) {
76  unsigned char *data = new unsigned char(42);
77  NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data
78                                                length:dataLength
79                                           deallocator:^(void *bytes,
80                                                         NSUInteger length) {
81                                             delete (unsigned char *)bytes;
82                                           }]; // no-warning
83}
84
85void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
86  unichar *data = (unichar*)malloc(42);
87  NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
88}
89
90void testOffsetFree() {
91  int *p = (int *)malloc(sizeof(int));
92  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()'}}
93}
94
95void testRelinquished1() {
96  void *data = malloc(42);
97  NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1];
98  free(data); // expected-warning {{Attempt to free non-owned memory}}
99}
100
101void testRelinquished2() {
102  void *data = malloc(42);
103  NSData *nsdata;
104  free(data);
105  [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Use of memory after it is freed}}
106}
107
108@interface My
109+ (void)param:(void *)p;
110@end
111
112void testUseAfterFree() {
113  int *p = (int *)malloc(sizeof(int));
114  free(p);
115  [My param:p];  // expected-warning{{Use of memory after it is freed}}
116}
117
118void testNoCopy() {
119  char *p = (char *)calloc(1, sizeof(int));
120  CustomData *w = [CustomData somethingNoCopy:p]; // no-warning
121}
122
123void testFreeWhenDone() {
124  char *p = (char *)calloc(1, sizeof(int));
125  CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning
126}
127
128void testFreeWhenDonePositive() {
129  char *p = (char *)calloc(1, sizeof(int));
130  CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}}
131}
132
133void testFreeWhenDoneNoCopy() {
134  int *p = (int *)malloc(sizeof(int));
135  CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning
136}
137
138void testFreeWhenDoneNoCopyPositive() {
139  int *p = (int *)malloc(sizeof(int));
140  CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}}
141}
142
143// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
144void testNSDatafFreeWhenDone(NSUInteger dataLength) {
145  CFStringRef str;
146  char *bytes = (char*)malloc(12);
147  str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning
148  CFRelease(str); // default allocator also frees bytes
149}
150
151void stringWithExternalContentsExample(void) {
152#define BufferSize 1000
153    CFMutableStringRef mutStr;
154    UniChar *myBuffer;
155
156    myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar));
157
158    mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}}
159
160    CFRelease(mutStr);
161    //free(myBuffer);
162}
163
164// PR12101 : pointers can escape through custom deallocators set on creation of a container.
165void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) {
166  void *key = malloc(12);
167  void *val = malloc(12);
168  CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks);
169  CFDictionarySetValue(x, key, val);
170  return;// no-warning
171}
172
173NSData *radar10976702() {
174  void *bytes = malloc(10);
175  return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning
176}
177
178void testBlocks() {
179  int *x= (int*)malloc(sizeof(int));
180  int (^myBlock)(int) = ^(int num) {
181    free(x);
182    return num;
183  };
184  myBlock(3);
185}
186
187// Test NSMapInsert.
188@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration>
189@end
190extern void *NSMapGet(NSMapTable *table, const void *key);
191extern void NSMapInsert(NSMapTable *table, const void *key, const void *value);
192extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value);
193char *strdup(const char *s);
194
195NSString * radar11152419(NSString *string1, NSMapTable *map) {
196    const char *strkey = "key";
197    NSString *string = ( NSString *)NSMapGet(map, strkey);
198    if (!string) {
199        string = [string1 copy];
200        NSMapInsert(map, strdup(strkey), (void*)string); // no warning
201        NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning
202    }
203    return string;
204}
205
206// Test that we handle pointer escaping through OSAtomicEnqueue.
207typedef volatile struct {
208 void *opaque1;
209 long opaque2;
210} OSQueueHead;
211extern "C" void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
212static inline void radar11111210(OSQueueHead *pool) {
213    void *newItem = malloc(4);
214    OSAtomicEnqueue(pool, newItem, 4);
215}
216
217// Pointer might escape through CGDataProviderCreateWithData
218typedef struct CGDataProvider *CGDataProviderRef;
219typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data,
220    size_t size);
221extern CGDataProviderRef CGDataProviderCreateWithData(void *info,
222    const void *data, size_t size,
223    CGDataProviderReleaseDataCallback releaseData)
224    __attribute__((visibility("default")));
225void *calloc(size_t, size_t);
226
227static void releaseDataCallback (void *info, const void *data, size_t size) {
228#pragma unused (info, size)
229  free((void*)data);
230}
231void testCGDataProviderCreateWithData() {
232  void* b = calloc(8, 8);
233  CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback);
234}
235
236// Assume that functions which take a function pointer can free memory even if
237// they are defined in system headers and take the const pointer to the
238// allocated memory.
239extern CGDataProviderRef UnknownFunWithCallback(void *info,
240    const void *data, size_t size,
241    CGDataProviderReleaseDataCallback releaseData)
242    __attribute__((visibility("default")));
243void testUnknownFunWithCallBack() {
244  void* b = calloc(8, 8);
245  CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback);
246}
247
248// Test blocks.
249void acceptBlockParam(void *, void (^block)(void *), unsigned);
250void testCallWithBlockCallback() {
251  void *l = malloc(12);
252  acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
253}
254
255// Test blocks in system headers.
256void testCallWithBlockCallbackInSystem() {
257  void *l = malloc(12);
258  SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
259}
260
261// Test escape into NSPointerArray. PR13140
262void foo(NSPointerArray* pointerArray) {
263
264  void* p1 = malloc (1024);
265  if (p1) {
266    [pointerArray addPointer:p1];
267  }
268
269  void* p2 = malloc (1024);
270  if (p2) {
271    [pointerArray insertPointer:p2 atIndex:1];
272  }
273
274  void* p3 = malloc (1024);
275  if (p3) {
276    [pointerArray replacePointerAtIndex:1 withPointer:p3];
277  }
278
279  // Freeing the buffer is allowed.
280  void* buffer = [pointerArray pointerAtIndex:0];
281  free(buffer);
282}
283
284void noCrashOnVariableArgumentSelector() {
285  NSMutableString *myString = [NSMutableString stringWithString:@"some text"];
286  [myString appendFormat:@"some text = %d", 3];
287}
288
289void test12365078_check() {
290  unichar *characters = (unichar*)malloc(12);
291  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
292  if (!string) free(characters); // no-warning
293}
294
295void test12365078_nocheck() {
296  unichar *characters = (unichar*)malloc(12);
297  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
298}
299
300void test12365078_false_negative() {
301  unichar *characters = (unichar*)malloc(12);
302  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
303  if (!string) {;}
304}
305
306void test12365078_no_malloc(unichar *characters) {
307  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
308  if (!string) {free(characters);}
309}
310
311NSString *test12365078_no_malloc_returnValue(unichar *characters) {
312  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
313  if (!string) {
314    return 0; // no-warning
315  }
316  return string;
317}
318
319void test12365078_nocheck_nomalloc(unichar *characters) {
320  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
321  free(characters); // expected-warning {{Attempt to free non-owned memory}}
322}
323
324void test12365078_nested(unichar *characters) {
325  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
326  if (!string) {
327    NSString *string2 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
328    if (!string2) {
329      NSString *string3 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
330      if (!string3) {
331        NSString *string4 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
332        if (!string4)
333          free(characters);
334      }
335    }
336  }
337}
338
339void test12365078_check_positive() {
340  unichar *characters = (unichar*)malloc(12);
341  NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
342  if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}}
343}
344
345void *test_reinterpret_cast_to_block() {
346  // Used to leak because the pointer was disappearing
347  // during the reinterpret_cast.
348  using BlockPtrTy = void (^)();
349  struct Block {};
350  Block* block = static_cast<Block*>(malloc(sizeof(Block)));
351  BlockPtrTy blockPtr = reinterpret_cast<BlockPtrTy>(block); // no-warning
352  return blockPtr;
353}
354