blob: 23297ec97cbd8556a6151246040240386f863772 [file] [log] [blame]
Anna Zaks9fe80982012-03-22 00:57:20 +00001// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
Anna Zaks7ac344a2012-02-24 23:56:53 +00002#include "system-header-simulator-objc.h"
Anna Zaks33c364b2012-02-16 22:26:15 +00003
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];
Anna Zaks33c364b2012-02-16 22:26:15 +000012}
13
Anna Zaks7ac344a2012-02-24 23:56:53 +000014void 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
24
25void testNSStringFreeWhenDoneYES(NSUInteger dataLength) {
26 unsigned char *data = (unsigned char *)malloc(42);
27 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning
28}
29
30void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) {
31 unichar *data = (unichar*)malloc(42);
32 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
33}
34
35
36void testNSDataFreeWhenDoneNO(NSUInteger dataLength) {
37 unsigned char *data = (unsigned char *)malloc(42);
38 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
39}
40
41void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) {
42 unsigned char *data = (unsigned char *)malloc(42);
43 NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
44}
45
46
47void testNSStringFreeWhenDoneNO(NSUInteger dataLength) {
48 unsigned char *data = (unsigned char *)malloc(42);
49 NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}}
50}
51
52void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
53 unichar *data = (unichar*)malloc(42);
54 NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
55}
56
Anna Zaks0d6989b2012-06-22 02:04:31 +000057void testRelinquished1() {
58 void *data = malloc(42);
59 NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1];
60 free(data); // expected-warning {{Attempt to free non-owned memory}}
61}
62
63void testRelinquished2() {
64 void *data = malloc(42);
65 NSData *nsdata;
66 free(data);
67 [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Attempt to free released memory}}
Anna Zaks33c364b2012-02-16 22:26:15 +000068}
Anna Zaks06a77fc2012-02-28 01:54:22 +000069
Anna Zakse0c03ca2012-02-29 18:42:47 +000070// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
Anna Zaks06a77fc2012-02-28 01:54:22 +000071void testNSDatafFreeWhenDone(NSUInteger dataLength) {
72 CFStringRef str;
73 char *bytes = (char*)malloc(12);
74 str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning
75 CFRelease(str); // default allocator also frees bytes
76}
77
78void stringWithExternalContentsExample(void) {
79#define BufferSize 1000
80 CFMutableStringRef mutStr;
81 UniChar *myBuffer;
82
83 myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar));
84
85 mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}}
86
87 CFRelease(mutStr);
88 //free(myBuffer);
89}
Anna Zakse0c03ca2012-02-29 18:42:47 +000090
91// PR12101 : pointers can escape through custom deallocators set on creation of a container.
92void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) {
93 void *key = malloc(12);
94 void *val = malloc(12);
95 CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks);
96 CFDictionarySetValue(x, key, val);
97 return;// no-warning
98}
Anna Zaks12a8b902012-03-05 17:42:10 +000099
100NSData *radar10976702() {
101 void *bytes = malloc(10);
102 return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning
103}
104
Anna Zaks9fe80982012-03-22 00:57:20 +0000105void testBlocks() {
106 int *x= (int*)malloc(sizeof(int));
107 int (^myBlock)(int) = ^(int num) {
108 free(x);
109 return num;
110 };
111 myBlock(3);
112}
113
Anna Zaks90ab9bf2012-03-30 05:48:16 +0000114// Test NSMapInsert.
115@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration>
116@end
117extern void *NSMapGet(NSMapTable *table, const void *key);
118extern void NSMapInsert(NSMapTable *table, const void *key, const void *value);
119extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value);
120char *strdup(const char *s);
121
122NSString * radar11152419(NSString *string1, NSMapTable *map) {
123 const char *strkey = "key";
124 NSString *string = ( NSString *)NSMapGet(map, strkey);
125 if (!string) {
126 string = [string1 copy];
127 NSMapInsert(map, strdup(strkey), (void*)string); // no warning
128 NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning
129 }
130 return string;
131}
132
Anna Zaksa651c402012-03-26 18:18:39 +0000133// Test that we handle pointer escaping through OSAtomicEnqueue.
134typedef volatile struct {
135 void *opaque1;
136 long opaque2;
137} OSQueueHead;
138void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
139static inline void radar11111210(OSQueueHead *pool) {
140 void *newItem = malloc(4);
141 OSAtomicEnqueue(pool, newItem, 4);
142}
143
Anna Zakse8628c52012-04-06 01:00:47 +0000144// Pointer might escape through CGDataProviderCreateWithData (radar://11187558).
145typedef struct CGDataProvider *CGDataProviderRef;
146typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data,
147 size_t size);
148extern CGDataProviderRef CGDataProviderCreateWithData(void *info,
149 const void *data, size_t size,
150 CGDataProviderReleaseDataCallback releaseData)
151 __attribute__((visibility("default")));
152void *calloc(size_t, size_t);
153
154static void releaseDataCallback (void *info, const void *data, size_t size) {
155#pragma unused (info, size)
156 free((void*)data);
157}
158void testCGDataProviderCreateWithData() {
159 void* b = calloc(8, 8);
160 CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback);
Anna Zaks228f9c72012-05-03 23:50:28 +0000161}
162
163// Assume that functions which take a function pointer can free memory even if
164// they are defined in system headers and take the const pointer to the
165// allocated memory. (radar://11160612)
166extern CGDataProviderRef UnknownFunWithCallback(void *info,
167 const void *data, size_t size,
168 CGDataProviderReleaseDataCallback releaseData)
169 __attribute__((visibility("default")));
170void testUnknownFunWithCallBack() {
171 void* b = calloc(8, 8);
172 CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback);
173}
174
175// Test blocks.
176void acceptBlockParam(void *, void (^block)(void *), unsigned);
177void testCallWithBlockCallback() {
178 void *l = malloc(12);
179 acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
180}
181
182// Test blocks in system headers.
183void testCallWithBlockCallbackInSystem() {
184 void *l = malloc(12);
185 SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
Anna Zaks42908c72012-06-19 05:10:32 +0000186}
187
188// Test escape into NSPointerArray. radar://11691035, PR13140
189void foo(NSPointerArray* pointerArray) {
190
191 void* p1 = malloc (1024);
192 if (p1) {
193 [pointerArray addPointer:p1];
194 }
195
196 void* p2 = malloc (1024);
197 if (p2) {
198 [pointerArray insertPointer:p2 atIndex:1];
199 }
200
201 void* p3 = malloc (1024);
202 if (p3) {
203 [pointerArray replacePointerAtIndex:1 withPointer:p3];
204 }
205
206 // Freeing the buffer is allowed.
207 void* buffer = [pointerArray pointerAtIndex:0];
208 free(buffer);
Anna Zakse8628c52012-04-06 01:00:47 +0000209}