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