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