[analyzer] Malloc: reason about the ObjC messages and C++.
Assume none of the ObjC messages defined in system headers free memory,
except for the ones containing 'freeWhenDone' selector. Currently, just
assume that the region escapes to the messages with 'freeWhenDone'
(ideally, we want to treat it as 'free()').
For now, always assume that regions escape when passed to C++ methods.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151410 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index ef3d1de..efab640 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -1,61 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
-
-typedef unsigned int UInt32;
-typedef signed long CFIndex;
-typedef signed char BOOL;
-typedef unsigned long NSUInteger;
-@class NSString, Protocol;
-extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
-typedef struct _NSZone NSZone;
-@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
-@protocol NSObject
-- (BOOL)isEqual:(id)object;
-- (id)retain;
-- (oneway void)release;
-- (id)autorelease;
-- (id)init;
-@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
-@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
-@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
-@end
-@interface NSObject <NSObject> {}
-+ (id)allocWithZone:(NSZone *)zone;
-+ (id)alloc;
-- (void)dealloc;
-@end
-@interface NSObject (NSCoderMethods)
-- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
-@end
-extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
-typedef struct {
-}
-NSFastEnumerationState;
-@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
-@end @class NSString, NSDictionary;
-@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
-@end @interface NSNumber : NSValue - (char)charValue;
-- (id)initWithInt:(int)value;
-@end @class NSString;
-@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
-@end @interface NSArray (NSArrayCreation) + (id)array;
-@end @interface NSAutoreleasePool : NSObject {
-}
-- (void)drain;
-@end extern NSString * const NSBundleDidLoadNotification;
-typedef double NSTimeInterval;
-@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
-@end typedef unsigned short unichar;
-@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
-- (NSUInteger)length;
-- (NSString *)stringByAppendingString:(NSString *)aString;
-- ( const char *)UTF8String;
-- (id)initWithUTF8String:(const char *)nullTerminatedCString;
-+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
-@end @class NSString, NSURL, NSError;
-@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
-+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
-+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
-@end
+#include "system-header-simulator-objc.h"
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@@ -68,8 +12,51 @@
free(data); // no warning
}
-// False Negative
-void testNSDatafFreeWhenDone(NSUInteger dataLength) {
+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
+}
+
+
+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}}
+}
+
+// TODO: False Negative.
+void testNSDatafFreeWhenDoneFN(NSUInteger dataLength) {
unsigned char *data = (unsigned char *)malloc(42);
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1];
free(data); // false negative
diff --git a/test/Analysis/system-header-simulator-objc.h b/test/Analysis/system-header-simulator-objc.h
new file mode 100644
index 0000000..9bfb793
--- /dev/null
+++ b/test/Analysis/system-header-simulator-objc.h
@@ -0,0 +1,75 @@
+#pragma clang system_header
+
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+- (id)init;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
+enum {
+ NSASCIIStringEncoding = 1,
+ NSNEXTSTEPStringEncoding = 2,
+ NSJapaneseEUCStringEncoding = 3,
+ NSUTF8StringEncoding = 4,
+ NSISOLatin1StringEncoding = 5,
+ NSSymbolStringEncoding = 6,
+ NSNonLossyASCIIStringEncoding = 7,
+};
+typedef NSUInteger NSStringEncoding;
+
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
+- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer;
+- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length;
+- (id)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end