2012-03-22 08:57:20 +08:00
|
|
|
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
|
2012-02-25 07:56:53 +08:00
|
|
|
#include "system-header-simulator-objc.h"
|
2012-02-17 06:26:15 +08:00
|
|
|
|
|
|
|
typedef __typeof(sizeof(int)) size_t;
|
|
|
|
void *malloc(size_t);
|
|
|
|
void free(void *);
|
|
|
|
|
|
|
|
// Done with headers. Start testing.
|
|
|
|
void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength];
|
|
|
|
}
|
|
|
|
|
2012-02-25 07:56:53 +08:00
|
|
|
void testNSDataFreeWhenDoneYES(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
|
|
|
|
}
|
|
|
|
|
2012-06-23 06:42:30 +08:00
|
|
|
void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) {
|
|
|
|
unichar *data = (unichar*)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1];
|
|
|
|
free(data); //expected-warning {{Attempt to free non-owned memory}}
|
|
|
|
}
|
2012-02-25 07:56:53 +08:00
|
|
|
|
|
|
|
void testNSStringFreeWhenDoneYES(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) {
|
|
|
|
unichar *data = (unichar*)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void testNSDataFreeWhenDoneNO(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void testNSStringFreeWhenDoneNO(NSUInteger dataLength) {
|
|
|
|
unsigned char *data = (unsigned char *)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
|
|
|
|
unichar *data = (unichar*)malloc(42);
|
|
|
|
NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
|
|
|
|
}
|
|
|
|
|
2012-06-22 10:04:31 +08:00
|
|
|
void testRelinquished1() {
|
|
|
|
void *data = malloc(42);
|
|
|
|
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1];
|
|
|
|
free(data); // expected-warning {{Attempt to free non-owned memory}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testRelinquished2() {
|
|
|
|
void *data = malloc(42);
|
|
|
|
NSData *nsdata;
|
|
|
|
free(data);
|
|
|
|
[NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Attempt to free released memory}}
|
2012-02-17 06:26:15 +08:00
|
|
|
}
|
2012-02-28 09:54:22 +08:00
|
|
|
|
2012-03-01 02:42:47 +08:00
|
|
|
// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
|
2012-02-28 09:54:22 +08:00
|
|
|
void testNSDatafFreeWhenDone(NSUInteger dataLength) {
|
|
|
|
CFStringRef str;
|
|
|
|
char *bytes = (char*)malloc(12);
|
|
|
|
str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning
|
|
|
|
CFRelease(str); // default allocator also frees bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
void stringWithExternalContentsExample(void) {
|
|
|
|
#define BufferSize 1000
|
|
|
|
CFMutableStringRef mutStr;
|
|
|
|
UniChar *myBuffer;
|
|
|
|
|
|
|
|
myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar));
|
|
|
|
|
|
|
|
mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}}
|
|
|
|
|
|
|
|
CFRelease(mutStr);
|
|
|
|
//free(myBuffer);
|
|
|
|
}
|
2012-03-01 02:42:47 +08:00
|
|
|
|
|
|
|
// PR12101 : pointers can escape through custom deallocators set on creation of a container.
|
|
|
|
void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) {
|
|
|
|
void *key = malloc(12);
|
|
|
|
void *val = malloc(12);
|
|
|
|
CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
|
CFDictionarySetValue(x, key, val);
|
|
|
|
return;// no-warning
|
|
|
|
}
|
2012-03-06 01:42:10 +08:00
|
|
|
|
|
|
|
NSData *radar10976702() {
|
|
|
|
void *bytes = malloc(10);
|
|
|
|
return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning
|
|
|
|
}
|
|
|
|
|
2012-03-22 08:57:20 +08:00
|
|
|
void testBlocks() {
|
|
|
|
int *x= (int*)malloc(sizeof(int));
|
|
|
|
int (^myBlock)(int) = ^(int num) {
|
|
|
|
free(x);
|
|
|
|
return num;
|
|
|
|
};
|
|
|
|
myBlock(3);
|
|
|
|
}
|
|
|
|
|
2012-03-30 13:48:16 +08:00
|
|
|
// Test NSMapInsert.
|
|
|
|
@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration>
|
|
|
|
@end
|
|
|
|
extern void *NSMapGet(NSMapTable *table, const void *key);
|
|
|
|
extern void NSMapInsert(NSMapTable *table, const void *key, const void *value);
|
|
|
|
extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value);
|
|
|
|
char *strdup(const char *s);
|
|
|
|
|
|
|
|
NSString * radar11152419(NSString *string1, NSMapTable *map) {
|
|
|
|
const char *strkey = "key";
|
|
|
|
NSString *string = ( NSString *)NSMapGet(map, strkey);
|
|
|
|
if (!string) {
|
|
|
|
string = [string1 copy];
|
|
|
|
NSMapInsert(map, strdup(strkey), (void*)string); // no warning
|
|
|
|
NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning
|
|
|
|
}
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
2012-03-27 02:18:39 +08:00
|
|
|
// Test that we handle pointer escaping through OSAtomicEnqueue.
|
|
|
|
typedef volatile struct {
|
|
|
|
void *opaque1;
|
|
|
|
long opaque2;
|
|
|
|
} OSQueueHead;
|
|
|
|
void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
|
|
|
|
static inline void radar11111210(OSQueueHead *pool) {
|
|
|
|
void *newItem = malloc(4);
|
|
|
|
OSAtomicEnqueue(pool, newItem, 4);
|
|
|
|
}
|
|
|
|
|
2012-04-06 09:00:47 +08:00
|
|
|
// Pointer might escape through CGDataProviderCreateWithData (radar://11187558).
|
|
|
|
typedef struct CGDataProvider *CGDataProviderRef;
|
|
|
|
typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data,
|
|
|
|
size_t size);
|
|
|
|
extern CGDataProviderRef CGDataProviderCreateWithData(void *info,
|
|
|
|
const void *data, size_t size,
|
|
|
|
CGDataProviderReleaseDataCallback releaseData)
|
|
|
|
__attribute__((visibility("default")));
|
|
|
|
void *calloc(size_t, size_t);
|
|
|
|
|
|
|
|
static void releaseDataCallback (void *info, const void *data, size_t size) {
|
|
|
|
#pragma unused (info, size)
|
|
|
|
free((void*)data);
|
|
|
|
}
|
|
|
|
void testCGDataProviderCreateWithData() {
|
|
|
|
void* b = calloc(8, 8);
|
|
|
|
CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback);
|
2012-05-04 07:50:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Assume that functions which take a function pointer can free memory even if
|
|
|
|
// they are defined in system headers and take the const pointer to the
|
|
|
|
// allocated memory. (radar://11160612)
|
|
|
|
extern CGDataProviderRef UnknownFunWithCallback(void *info,
|
|
|
|
const void *data, size_t size,
|
|
|
|
CGDataProviderReleaseDataCallback releaseData)
|
|
|
|
__attribute__((visibility("default")));
|
|
|
|
void testUnknownFunWithCallBack() {
|
|
|
|
void* b = calloc(8, 8);
|
|
|
|
CGDataProviderRef p = UnknownFunWithCallback(0, b, 8*8, releaseDataCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test blocks.
|
|
|
|
void acceptBlockParam(void *, void (^block)(void *), unsigned);
|
|
|
|
void testCallWithBlockCallback() {
|
|
|
|
void *l = malloc(12);
|
|
|
|
acceptBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test blocks in system headers.
|
|
|
|
void testCallWithBlockCallbackInSystem() {
|
|
|
|
void *l = malloc(12);
|
|
|
|
SystemHeaderFunctionWithBlockParam(l, ^(void *i) { free(i); }, sizeof(char *));
|
2012-06-19 13:10:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test escape into NSPointerArray. radar://11691035, PR13140
|
|
|
|
void foo(NSPointerArray* pointerArray) {
|
|
|
|
|
|
|
|
void* p1 = malloc (1024);
|
|
|
|
if (p1) {
|
|
|
|
[pointerArray addPointer:p1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void* p2 = malloc (1024);
|
|
|
|
if (p2) {
|
|
|
|
[pointerArray insertPointer:p2 atIndex:1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void* p3 = malloc (1024);
|
|
|
|
if (p3) {
|
|
|
|
[pointerArray replacePointerAtIndex:1 withPointer:p3];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Freeing the buffer is allowed.
|
|
|
|
void* buffer = [pointerArray pointerAtIndex:0];
|
|
|
|
free(buffer);
|
2012-06-23 06:08:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void noCrashOnVariableArgumentSelector() {
|
|
|
|
NSMutableString *myString = [NSMutableString stringWithString:@"some text"];
|
|
|
|
[myString appendFormat:@"some text = %d", 3];
|
2012-04-06 09:00:47 +08:00
|
|
|
}
|