From ec2b103c267a06a66e926f62cd96767b280f5cf5 Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Tue, 2 Jun 2009 17:58:47 +0000 Subject: Import Clang, at r72732. --- test/Analysis/CFDateGC.m | 87 +++ test/Analysis/CFNumber.c | 31 + test/Analysis/CFRetainRelease_NSAssertionHandler.m | 67 ++ test/Analysis/CGColorSpace.c | 21 + test/Analysis/CheckNSError.m | 59 ++ test/Analysis/MissingDealloc.m | 117 ++++ test/Analysis/NSPanel.m | 90 +++ test/Analysis/NSString.m | 335 ++++++++++ test/Analysis/NSWindow.m | 89 +++ test/Analysis/NoReturn.m | 82 +++ test/Analysis/ObjCProperties.m | 25 + test/Analysis/ObjCRetSigs.m | 25 + test/Analysis/PR2599.m | 64 ++ test/Analysis/PR2978.m | 61 ++ test/Analysis/PR3991.m | 67 ++ test/Analysis/array-struct.c | 150 +++++ test/Analysis/basicstore_wine_crash.c | 11 + test/Analysis/casts.c | 16 + test/Analysis/casts.m | 22 + test/Analysis/cfref_PR2519.c | 48 ++ test/Analysis/cfref_rdar6080742.c | 58 ++ test/Analysis/complex.c | 21 + test/Analysis/conditional-op-missing-lhs.c | 26 + test/Analysis/dead-stores.c | 175 +++++ test/Analysis/dead-stores.m | 36 ++ test/Analysis/delegates.m | 114 ++++ test/Analysis/exercise-ps.c | 25 + test/Analysis/fields.c | 10 + test/Analysis/func.c | 17 + test/Analysis/misc-ps-64.m | 49 ++ test/Analysis/misc-ps-basic-store.m | 21 + test/Analysis/misc-ps-eager-assume.m | 79 +++ test/Analysis/misc-ps-ranges.m | 23 + test/Analysis/misc-ps-region-store.m | 70 ++ test/Analysis/misc-ps.m | 287 +++++++++ ...il-receiver-undefined-larger-than-voidptr-ret.m | 67 ++ test/Analysis/no-exit-cfg.c | 19 + test/Analysis/no-outofbounds-basicstore.c | 7 + test/Analysis/null-deref-ps-region.c | 14 + test/Analysis/null-deref-ps.c | 265 ++++++++ test/Analysis/outofbound.c | 7 + test/Analysis/override-werror.c | 15 + test/Analysis/pr4209.m | 70 ++ test/Analysis/pr_2542_rdar_6793404.m | 68 ++ test/Analysis/pr_4164.c | 41 ++ test/Analysis/ptr-arith.c | 34 + test/Analysis/rdar-6442306-1.m | 31 + test/Analysis/rdar-6539791.c | 47 ++ test/Analysis/rdar-6540084.m | 36 ++ test/Analysis/rdar-6541136-region.c | 19 + test/Analysis/rdar-6541136.c | 20 + test/Analysis/rdar-6562655.m | 63 ++ test/Analysis/rdar-6582778-basic-store.c | 22 + ...dar-6600344-nil-receiver-undefined-struct-ret.m | 25 + test/Analysis/refcnt_naming.m | 62 ++ test/Analysis/region-1.m | 90 +++ test/Analysis/region-only-test.c | 13 + test/Analysis/retain-release-basic-store.m | 102 +++ test/Analysis/retain-release-gc-only.m | 161 +++++ test/Analysis/retain-release-region-store.m | 118 ++++ test/Analysis/retain-release.m | 708 +++++++++++++++++++++ test/Analysis/stack-addr-ps.c | 44 ++ test/Analysis/uninit-msg-expr.m | 58 ++ test/Analysis/uninit-ps-rdar6145427.m | 37 ++ test/Analysis/uninit-vals-ps-region.c | 17 + test/Analysis/uninit-vals-ps.c | 85 +++ test/Analysis/uninit-vals.c | 53 ++ test/Analysis/uninit-vals.m | 25 + test/Analysis/unused-ivars.m | 10 + test/Analysis/xfail-no-outofbounds.c | 7 + test/Analysis/xfail_regionstore_wine_crash.c | 12 + 71 files changed, 4950 insertions(+) create mode 100644 test/Analysis/CFDateGC.m create mode 100644 test/Analysis/CFNumber.c create mode 100644 test/Analysis/CFRetainRelease_NSAssertionHandler.m create mode 100644 test/Analysis/CGColorSpace.c create mode 100644 test/Analysis/CheckNSError.m create mode 100644 test/Analysis/MissingDealloc.m create mode 100644 test/Analysis/NSPanel.m create mode 100644 test/Analysis/NSString.m create mode 100644 test/Analysis/NSWindow.m create mode 100644 test/Analysis/NoReturn.m create mode 100644 test/Analysis/ObjCProperties.m create mode 100644 test/Analysis/ObjCRetSigs.m create mode 100644 test/Analysis/PR2599.m create mode 100644 test/Analysis/PR2978.m create mode 100644 test/Analysis/PR3991.m create mode 100644 test/Analysis/array-struct.c create mode 100644 test/Analysis/basicstore_wine_crash.c create mode 100644 test/Analysis/casts.c create mode 100644 test/Analysis/casts.m create mode 100644 test/Analysis/cfref_PR2519.c create mode 100644 test/Analysis/cfref_rdar6080742.c create mode 100644 test/Analysis/complex.c create mode 100644 test/Analysis/conditional-op-missing-lhs.c create mode 100644 test/Analysis/dead-stores.c create mode 100644 test/Analysis/dead-stores.m create mode 100644 test/Analysis/delegates.m create mode 100644 test/Analysis/exercise-ps.c create mode 100644 test/Analysis/fields.c create mode 100644 test/Analysis/func.c create mode 100644 test/Analysis/misc-ps-64.m create mode 100644 test/Analysis/misc-ps-basic-store.m create mode 100644 test/Analysis/misc-ps-eager-assume.m create mode 100644 test/Analysis/misc-ps-ranges.m create mode 100644 test/Analysis/misc-ps-region-store.m create mode 100644 test/Analysis/misc-ps.m create mode 100644 test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m create mode 100644 test/Analysis/no-exit-cfg.c create mode 100644 test/Analysis/no-outofbounds-basicstore.c create mode 100644 test/Analysis/null-deref-ps-region.c create mode 100644 test/Analysis/null-deref-ps.c create mode 100644 test/Analysis/outofbound.c create mode 100644 test/Analysis/override-werror.c create mode 100644 test/Analysis/pr4209.m create mode 100644 test/Analysis/pr_2542_rdar_6793404.m create mode 100644 test/Analysis/pr_4164.c create mode 100644 test/Analysis/ptr-arith.c create mode 100644 test/Analysis/rdar-6442306-1.m create mode 100644 test/Analysis/rdar-6539791.c create mode 100644 test/Analysis/rdar-6540084.m create mode 100644 test/Analysis/rdar-6541136-region.c create mode 100644 test/Analysis/rdar-6541136.c create mode 100644 test/Analysis/rdar-6562655.m create mode 100644 test/Analysis/rdar-6582778-basic-store.c create mode 100644 test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m create mode 100644 test/Analysis/refcnt_naming.m create mode 100644 test/Analysis/region-1.m create mode 100644 test/Analysis/region-only-test.c create mode 100644 test/Analysis/retain-release-basic-store.m create mode 100644 test/Analysis/retain-release-gc-only.m create mode 100644 test/Analysis/retain-release-region-store.m create mode 100644 test/Analysis/retain-release.m create mode 100644 test/Analysis/stack-addr-ps.c create mode 100644 test/Analysis/uninit-msg-expr.m create mode 100644 test/Analysis/uninit-ps-rdar6145427.m create mode 100644 test/Analysis/uninit-vals-ps-region.c create mode 100644 test/Analysis/uninit-vals-ps.c create mode 100644 test/Analysis/uninit-vals.c create mode 100644 test/Analysis/uninit-vals.m create mode 100644 test/Analysis/unused-ivars.m create mode 100644 test/Analysis/xfail-no-outofbounds.c create mode 100644 test/Analysis/xfail_regionstore_wine_crash.c (limited to 'test/Analysis') diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m new file mode 100644 index 000000000000..dfc736627bfc --- /dev/null +++ b/test/Analysis/CFDateGC.m @@ -0,0 +1,87 @@ +// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -analyzer-constraints=basic %s && +// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -analyzer-constraints=range %s && +// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -disable-free %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h and CoreFoundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not directly including [Core]Foundation.h directly makes this test case +// both svelte and portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef const void * CFTypeRef; +void CFRelease(CFTypeRef cf); +CFTypeRef CFRetain(CFTypeRef cf); +CFTypeRef CFMakeCollectable(CFTypeRef cf); +typedef const struct __CFAllocator * CFAllocatorRef; +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate); +typedef struct objc_object {} *id; +typedef signed char BOOL; +static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef cf) {} +@protocol NSObject - (BOOL)isEqual:(id)object; +- (oneway void)release; +- (id)retain; +@end +@class NSArray; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +CFAbsoluteTime f1_use_after_release() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + CFRetain(date); + [NSMakeCollectable(date) release]; + CFDateGetAbsoluteTime(date); // no-warning + CFRelease(date); + t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}} + return t; +} + +// The following two test cases verifies that CFMakeCollectable is a no-op +// in non-GC mode and a "release" in GC mode. +CFAbsoluteTime f2_use_after_release() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + CFRetain(date); + [(id) CFMakeCollectable(date) release]; + CFDateGetAbsoluteTime(date); // no-warning + CFRelease(date); + t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}} + return t; +} + +CFAbsoluteTime f2_noleak() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + CFRetain(date); + [(id) CFMakeCollectable(date) release]; + CFDateGetAbsoluteTime(date); // no-warning + t = CFDateGetAbsoluteTime(date); // no-warning + CFRelease(date); // no-warning + return t; +} + +void f3_leak_with_gc() { + CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning 2 {{leak}} + [[(id) date retain] release]; +} + +// The following test case verifies that we "stop tracking" a retained object +// when it is passed as an argument to an implicitly defined function. +CFAbsoluteTime f4() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + CFRetain(date); + some_implicitly_defined_function_stop_tracking(date); // no-warning + return t; +} diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c new file mode 100644 index 000000000000..f62d2ab569d4 --- /dev/null +++ b/test/Analysis/CFNumber.c @@ -0,0 +1,31 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s + +typedef signed long CFIndex; +typedef const struct __CFAllocator * CFAllocatorRef; +enum { kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, + kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, + kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, + kCFNumberCharType = 7, kCFNumberShortType = 8, + kCFNumberIntType = 9, kCFNumberLongType = 10, + kCFNumberLongLongType = 11, kCFNumberFloatType = 12, + kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, + kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, + kCFNumberMaxType = 16 }; +typedef CFIndex CFNumberType; +typedef const struct __CFNumber * CFNumberRef; +extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); + +CFNumberRef f1(unsigned char x) { + return CFNumberCreate(0, kCFNumberSInt16Type, &x); // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage.}} +} + +CFNumberRef f2(unsigned short x) { + return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost.}} +} + +CFNumberRef f3(unsigned i) { + return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer.}} +} diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m new file mode 100644 index 000000000000..1ff950725c02 --- /dev/null +++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m @@ -0,0 +1,67 @@ +// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic && +// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic && +// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=region && +// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=region + +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef int NSInteger; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} - (id)init; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject +- (NSUInteger)length; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end extern NSString * const NSBundleDidLoadNotification; +@interface NSAssertionHandler : NSObject {} ++ (NSAssertionHandler *)currentHandler; +- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...; +@end +extern NSString * const NSConnectionReplyMode; + +//----------------------------------------------------------------------------// +// The following test case was filed in PR 2593: +// http://llvm.org/bugs/show_bug.cgi?id=2593 +// +// There should be no null dereference flagged by the checker because of +// NSParameterAssert and NSAssert. + + +@interface TestAssert : NSObject {} +@end + +@implementation TestAssert + +- (id)initWithPointer: (int*)x +{ + // Expansion of: NSParameterAssert( x != 0 ); + do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:"CFRetainRelease_NSAssertionHandler.m"] lineNumber:21 description:(@"Invalid parameter not satisfying: %s"), ("x != 0"), (0), (0), (0), (0)]; } } while(0); + + if( (self = [super init]) != 0 ) + { + *x = 1; // no-warning + } + + return self; +} + +- (id)initWithPointer2: (int*)x +{ + // Expansion of: NSAssert( x != 0, @"" ); + do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:"CFRetainRelease_NSAssertionHandler.m"] lineNumber:33 description:((@"")), (0), (0), (0), (0), (0)]; } } while(0); + + if( (self = [super init]) != 0 ) + { + *x = 1; // no-warning + } + + return self; +} + +@end diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c new file mode 100644 index 000000000000..2887d47c5118 --- /dev/null +++ b/test/Analysis/CGColorSpace.c @@ -0,0 +1,21 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +typedef struct CGColorSpace *CGColorSpaceRef; +extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); +extern CGColorSpaceRef CGColorSpaceRetain(CGColorSpaceRef space); +extern void CGColorSpaceRelease(CGColorSpaceRef space); + +void f() { + CGColorSpaceRef X = CGColorSpaceCreateDeviceRGB(); // expected-warning{{leak}} + CGColorSpaceRetain(X); +} + +void fb() { + CGColorSpaceRef X = CGColorSpaceCreateDeviceRGB(); + CGColorSpaceRetain(X); + CGColorSpaceRelease(X); + CGColorSpaceRelease(X); // no-warning +} diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m new file mode 100644 index 000000000000..779b865aff8c --- /dev/null +++ b/test/Analysis/CheckNSError.m @@ -0,0 +1,59 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + + +typedef signed char BOOL; +typedef int NSInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} @end +@class NSDictionary; +@interface NSError : NSObject {} ++ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict; +@end +extern NSString * const NSXMLParserErrorDomain ; + +@interface A +- (void)myMethodWhichMayFail:(NSError **)error; +- (BOOL)myMethodWhichMayFail2:(NSError **)error; +@end + +@implementation A +- (void)myMethodWhichMayFail:(NSError **)error { // expected-warning {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occured.}} + *error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // expected-warning {{Potential null dereference.}} +} + +- (BOOL)myMethodWhichMayFail2:(NSError **)error { // no-warning + if (error) *error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // no-warning + return 0; +} +@end + +struct __CFError {}; +typedef struct __CFError* CFErrorRef; + +void foo(CFErrorRef* error) { // expected-warning {{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occured.}} + *error = 0; // expected-warning {{Potential null dereference.}} +} + +int f1(CFErrorRef* error) { + if (error) *error = 0; // no-warning + return 0; +} + +int f2(CFErrorRef* error) { + if (0 != error) *error = 0; // no-warning + return 0; +} + +int f3(CFErrorRef* error) { + if (error != 0) *error = 0; // no-warning + return 0; +} + + diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m new file mode 100644 index 000000000000..41498e56ec1d --- /dev/null +++ b/test/Analysis/MissingDealloc.m @@ -0,0 +1,117 @@ +// RUN: clang-cc -analyze -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s --verify +typedef signed char BOOL; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (Class)class; +@end + +@interface NSObject {} +- (void)dealloc; +- (id)init; +@end + +typedef struct objc_selector *SEL; + +// : 'myproperty' has kind 'assign' and thus the +// assignment through the setter does not perform a release. + +@interface MyObject : NSObject { + id _myproperty; +} +@property(assign) id myproperty; +@end + +@implementation MyObject +@synthesize myproperty=_myproperty; // no-warning +- (void)dealloc { + self.myproperty = 0; + [super dealloc]; +} +@end + +//===------------------------------------------------------------------------=== +// Don't warn about iVars that are selectors. + +@interface TestSELs : NSObject { + SEL a; + SEL b; +} + +@end + +@implementation TestSELs // no-warning +- (id)init { + if( (self = [super init]) ) { + a = @selector(a); + b = @selector(b); + } + + return self; +} +@end + +//===------------------------------------------------------------------------=== +// Don't warn about iVars that are IBOutlets. + +#ifndef IBOutlet +#define IBOutlet +#endif + +@class NSWindow; + +@interface HasOutlet : NSObject { +IBOutlet NSWindow *window; +} +@end + +@implementation HasOutlet // no-warning +@end + +//===------------------------------------------------------------------------=== +// +// Was bogus warning: "The '_myproperty' instance variable was not retained by a +// synthesized property but was released in 'dealloc'" + +@interface MyObject_rdar6380411 : NSObject { + id _myproperty; +} +@property(assign) id myproperty; +@end + +@implementation MyObject_rdar6380411 +@synthesize myproperty=_myproperty; +- (void)dealloc { + // Don't claim that myproperty is released since it the property + // has the 'assign' attribute. + self.myproperty = 0; // no-warning + [super dealloc]; +} +@end + +//===------------------------------------------------------------------------=== +// PR 3187: http://llvm.org/bugs/show_bug.cgi?id=3187 +// - Disable the missing -dealloc check for classes that subclass SenTestCase + +@class NSString; + +@interface SenTestCase : NSObject {} +@end + +@interface MyClassTest : SenTestCase { + NSString *resourcePath; +} +@end + +@interface NSBundle : NSObject {} ++ (NSBundle *)bundleForClass:(Class)aClass; +- (NSString *)resourcePath; +@end + +@implementation MyClassTest +- (void)setUp { + resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath]; +} +- (void)testXXX { + // do something which uses resourcepath +} +@end diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m new file mode 100644 index 000000000000..c4d4c22540f2 --- /dev/null +++ b/test/Analysis/NSPanel.m @@ -0,0 +1,90 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +// BEGIN delta-debugging reduced header stuff + +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (oneway void)release; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} ++ (id)alloc; +@end +typedef float CGFloat; +typedef struct _NSPoint {} NSRect; +static __inline__ __attribute__((always_inline)) NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) {} +typedef struct {} NSFastEnumerationState; +@protocol NSFastEnumeration +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end +@class NSString; +@interface NSArray : NSObject +- (NSUInteger)count; +@end +@interface NSMutableArray : NSArray +- (void)addObject:(id)anObject; +@end @class NSAppleEventDescriptor; +enum { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; +typedef NSUInteger NSBackingStoreType; +@interface NSResponder : NSObject {} @end +@protocol NSAnimatablePropertyContainer +- (id)animator; +@end +@protocol NSValidatedUserInterfaceItem +- (SEL)action; +@end +@protocol NSUserInterfaceValidations +- (BOOL)validateUserInterfaceItem:(id )anItem; +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +enum { NSBorderlessWindowMask = 0, NSTitledWindowMask = 1 << 0, NSClosableWindowMask = 1 << 1, NSMiniaturizableWindowMask = 1 << 2, NSResizableWindowMask = 1 << 3 }; +@interface NSWindow : NSResponder {} +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; +@end +extern NSString *NSWindowDidBecomeKeyNotification; +@interface NSPanel : NSWindow {} +@end +@class NSTableHeaderView; + +// END delta-debugging reduced header stuff + +@interface MyClass +{ + NSMutableArray *panels; +} +- (void)myMethod; +- (void)myMethod2; +@end + +@implementation MyClass // no-warning +- (void)myMethod +{ + NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:(BOOL)1]; + + [panels addObject:panel]; + + [panel release]; // no-warning +} +- (void)myMethod2 +{ + NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:(BOOL)1]; // no-warning + + [panels addObject:panel]; +} +@end + diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m new file mode 100644 index 000000000000..b707071990f8 --- /dev/null +++ b/test/Analysis/NSString.m @@ -0,0 +1,335 @@ +// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s + + +// NOTWORK: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// NOTWORK: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not directly including Foundation.h directly makes this test case +// both svelte and portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef int int32_t; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern CFTypeRef CFRetain(CFTypeRef cf); +void CFRelease(CFTypeRef cf); +typedef const struct __CFDictionary * CFDictionaryRef; +const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key); +extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...); +typedef signed char BOOL; +typedef int NSInteger; +typedef unsigned int NSUInteger; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef NSInteger NSComparisonResult; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (oneway void)release; +- (id)retain; +- (id)autorelease; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} +- (id)init; ++ (id)alloc; +@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; +typedef struct _NSRange {} NSRange; +@interface NSArray : NSObject +- (NSUInteger)count; +@end +@interface NSMutableArray : NSArray +- (void)addObject:(id)anObject; +- (id)initWithCapacity:(NSUInteger)numItems; +@end +typedef unsigned short unichar; +@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale; +typedef NSUInteger NSStringCompareOptions; +@interface NSString : NSObject - (NSUInteger)length; +- (NSComparisonResult)compare:(NSString *)string; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale; +- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string; +- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator; ++ (id)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); +@end +@interface NSSimpleCString : NSString {} @end +@interface NSConstantString : NSSimpleCString @end +extern void *_NSConstantStringClassReference; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +NSComparisonResult f1(NSString* s) { + NSString *aString = 0; + return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil.}} +} + +NSComparisonResult f2(NSString* s) { + NSString *aString = 0; + return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil.}} +} + +NSComparisonResult f3(NSString* s, NSStringCompareOptions op) { + NSString *aString = 0; + return [s compare:aString options:op]; // expected-warning {{Argument to 'NSString' method 'compare:options:' cannot be nil.}} +} + +NSComparisonResult f4(NSString* s, NSStringCompareOptions op, NSRange R) { + NSString *aString = 0; + return [s compare:aString options:op range:R]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:' cannot be nil.}} +} + +NSComparisonResult f5(NSString* s, NSStringCompareOptions op, NSRange R) { + NSString *aString = 0; + return [s compare:aString options:op range:R locale:0]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:locale:' cannot be nil.}} +} + +NSArray *f6(NSString* s) { + return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil.}} +} + +NSString* f7(NSString* s1, NSString* s2, NSString* s3) { + + NSString* s4 = (NSString*) + CFStringCreateWithFormat(kCFAllocatorDefault, 0, // expected-warning{{leak}} + (CFStringRef) __builtin___CFStringMakeConstantString("%@ %@ (%@)"), + s1, s2, s3); + + CFRetain(s4); + return s4; +} + +NSMutableArray* f8() { + + NSString* s = [[NSString alloc] init]; + NSMutableArray* a = [[NSMutableArray alloc] initWithCapacity:2]; + [a addObject:s]; + [s release]; // no-warning + return a; +} + +void f9() { + + NSString* s = [[NSString alloc] init]; + NSString* q = s; + [s release]; + [q release]; // expected-warning {{used after it is released}} +} + +NSString* f10() { + static NSString* s = 0; + if (!s) s = [[NSString alloc] init]; + return s; // no-warning +} + +// Test case for regression reported in . +// Essentially 's' should not be considered allocated on the false branch. +// This exercises the 'EvalAssume' logic in GRTransferFuncs (CFRefCount.cpp). +NSString* f11(CFDictionaryRef dict, const char* key) { + NSString* s = (NSString*) CFDictionaryGetValue(dict, key); + [s retain]; + if (s) { + [s release]; + } +} + +// Test case for passing a tracked object by-reference to a function we +// don't understand. +void unknown_function_f12(NSString** s); +void f12() { + NSString *string = [[NSString alloc] init]; + unknown_function_f12(&string); // no-warning +} + +// Test double release of CFString (PR 4014). +void f13(void) { + CFStringRef ref = CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); + CFRelease(ref); + CFRelease(ref); // expected-warning{{Reference-counted object is used after it is released}} +} + +// Test regular use of -autorelease +@interface TestAutorelease +-(NSString*) getString; +@end +@implementation TestAutorelease +-(NSString*) getString { + NSString *str = [[NSString alloc] init]; + return [str autorelease]; // no-warning +} +- (void)m1 +{ + NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + [s retain]; + [s autorelease]; +} +- (void)m2 +{ + NSString *s = [[[NSString alloc] init] autorelease]; // expected-warning{{leak}} + [s retain]; +} +- (void)m3 +{ + NSString *s = [[[NSString alloc] init] autorelease]; + [s retain]; + [s autorelease]; +} +- (void)m4 +{ + NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + [s retain]; +} +- (void)m5 +{ + NSString *s = [[NSString alloc] init]; + [s autorelease]; +} +@end + +@interface C1 : NSObject {} +- (NSString*) getShared; ++ (C1*) sharedInstance; +@end +@implementation C1 : NSObject {} +- (NSString*) getShared { + static NSString* s = 0; + if (!s) s = [[NSString alloc] init]; + return s; // no-warning +} ++ (C1 *)sharedInstance { + static C1 *sharedInstance = 0; + if (!sharedInstance) { + sharedInstance = [[C1 alloc] init]; + } + return sharedInstance; // no-warning +} +@end + +@interface SharedClass : NSObject ++ (id)sharedInstance; +- (id)notShared; +@end + +@implementation SharedClass + +- (id)_init { + if ((self = [super init])) { + NSLog(@"Bar"); + } + return self; +} + +- (id)notShared { + return [[SharedClass alloc] _init]; // expected-warning{{leak}} +} + ++ (id)sharedInstance { + static SharedClass *_sharedInstance = 0; + if (!_sharedInstance) { + _sharedInstance = [[SharedClass alloc] _init]; + } + return _sharedInstance; // no-warning +} +@end + +id testSharedClassFromFunction() { + return [[SharedClass alloc] _init]; // no-warning +} + +// Test OSCompareAndSwap +_Bool OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue ); +_Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue ); +extern BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation); + +void testOSCompareAndSwap() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!OSAtomicCompareAndSwapPtr(0, s, (void**) &old)) + [s release]; + else + [old release]; +} + +void testOSCompareAndSwap32Barrier() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!OSAtomicCompareAndSwap32Barrier((int32_t) 0, (int32_t) s, (int32_t*) &old)) + [s release]; + else + [old release]; +} + +void test_objc_atomicCompareAndSwap() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!objc_atomicCompareAndSwapPtr(0, s, &old)) + [s release]; + else + [old release]; +} + +// Test stringWithFormat () +void test_stringWithFormat() { + NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; + [string release]; + [string release]; // expected-warning{{Incorrect decrement of the reference count}} +} + +// Test isTrackedObjectType(). +typedef NSString* WonkyTypedef; +@interface TestIsTracked ++ (WonkyTypedef)newString; +@end + +void test_isTrackedObjectType(void) { + NSString *str = [TestIsTracked newString]; // expected-warning{{Potential leak}} +} + +// Test isTrackedCFObjectType(). +@interface TestIsCFTracked ++ (CFStringRef) badNewCFString; ++ (CFStringRef) newCFString; +@end + +@implementation TestIsCFTracked ++ (CFStringRef) newCFString { + return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // no-warning +} ++ (CFStringRef) badNewCFString { + return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // expected-warning{{leak}} +} + +// Test @synchronized +void test_synchronized(id x) { + @synchronized(x) { + NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}} + } +} + + diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m new file mode 100644 index 000000000000..9609c5260f53 --- /dev/null +++ b/test/Analysis/NSWindow.m @@ -0,0 +1,89 @@ +// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=range -verify %s + +// These declarations were reduced using Delta-Debugging from Foundation.h +// on Mac OS X. The test cases are below. + +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef unsigned int NSUInteger; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +@end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} + + (id)alloc; +@end +typedef float CGFloat; +typedef struct _NSPoint {} NSRect; +NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h); +enum { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; +typedef NSUInteger NSBackingStoreType; +@interface NSResponder : NSObject {} +@end +@protocol NSAnimatablePropertyContainer +- (id)animator; +@end +extern NSString *NSAnimationTriggerOrderIn ; +@class CIFilter, CALayer, NSDictionary, NSScreen, NSShadow, NSTrackingArea; +@interface NSView : NSResponder {} @end +@protocol NSValidatedUserInterfaceItem - (SEL)action; @end +@protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id )anItem; @end @class NSNotification, NSText, NSView, NSMutableSet, NSSet, NSDate; +enum { NSBorderlessWindowMask = 0, NSTitledWindowMask = 1 << 0, NSClosableWindowMask = 1 << 1, NSMiniaturizableWindowMask = 1 << 2, NSResizableWindowMask = 1 << 3 }; +@interface NSWindow : NSResponder { + struct __wFlags {} _wFlags; +} +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)screen; +- (void)orderFrontRegardless; +@end + +extern NSString *NSWindowDidBecomeKeyNotification; + +// Test cases. + +void f1() { + NSWindow *window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(0,0,100,100) + styleMask:NSTitledWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered + defer:0]; + + [window orderFrontRegardless]; // no-warning +} + +void f2() { + NSWindow *window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(0,0,100,100) + styleMask:NSTitledWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered + defer:0 + screen:0]; + + [window orderFrontRegardless]; // no-warning +} + +void f2b() { + // FIXME: NSWindow doesn't own itself until it is displayed. + NSWindow *window = [[NSWindow alloc] // no-warning + initWithContentRect:NSMakeRect(0,0,100,100) + styleMask:NSTitledWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered + defer:0 + screen:0]; + + [window orderFrontRegardless]; + + [window retain]; +} + + +void f3() { + // FIXME: For now we don't track NSWindow. + NSWindow *window = [NSWindow alloc]; // expected-warning{{never read}} +} diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m new file mode 100644 index 000000000000..a43f99bdd79b --- /dev/null +++ b/test/Analysis/NoReturn.m @@ -0,0 +1,82 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +#include + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not directly including Foundation.h directly makes this test case +// both svelte and portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject +- (NSUInteger)length; ++ (id)stringWithFormat:(NSString *)format, ...; +@end +@interface NSSimpleCString : NSString {} @end +@interface NSConstantString : NSSimpleCString @end +extern void *_NSConstantStringClassReference; +typedef double NSTimeInterval; +@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; @end +@class NSString, NSDictionary, NSArray; +@interface NSException : NSObject {} ++ (NSException *)exceptionWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo; +- (void)raise; +@end +@interface NSException (NSExceptionRaisingConveniences) ++ (void)raise:(NSString *)name format:(NSString *)format, ...; ++ (void)raise:(NSString *)name format:(NSString *)format arguments:(va_list)argList; +@end + +enum {NSPointerFunctionsStrongMemory = (0 << 0), NSPointerFunctionsZeroingWeakMemory = (1 << 0), NSPointerFunctionsOpaqueMemory = (2 << 0), NSPointerFunctionsMallocMemory = (3 << 0), NSPointerFunctionsMachVirtualMemory = (4 << 0), NSPointerFunctionsObjectPersonality = (0 << 8), NSPointerFunctionsOpaquePersonality = (1 << 8), NSPointerFunctionsObjectPointerPersonality = (2 << 8), NSPointerFunctionsCStringPersonality = (3 << 8), NSPointerFunctionsStructPersonality = (4 << 8), NSPointerFunctionsIntegerPersonality = (5 << 8), NSPointerFunctionsCopyIn = (1 << 16), }; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +int f1(int *x, NSString* s) { + + if (x) ++x; + + [NSException raise:@"Blah" format:[NSString stringWithFormat:@"Blah %@", s]]; + + return *x; // no-warning +} + +int f2(int *x, ...) { + + if (x) ++x; + va_list alist; + va_start(alist, x); + + [NSException raise:@"Blah" format:@"Blah %@" arguments:alist]; + + return *x; // no-warning +} + +int f3(int* x) { + + if (x) ++x; + + [[NSException exceptionWithName:@"My Exception" reason:@"Want to test exceptions." userInfo:0] raise]; + + return *x; // no-warning +} + diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m new file mode 100644 index 000000000000..7787a1d6ecdc --- /dev/null +++ b/test/Analysis/ObjCProperties.m @@ -0,0 +1,25 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic %s -verify && +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range %s -verify && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic %s -verify && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range %s -verify && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic %s -verify && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify + +// The point of this test cases is to exercise properties in the static +// analyzer + +@interface MyClass { +@private + id _X; +} +- (id)initWithY:(id)Y; +@property(copy, readwrite) id X; +@end + +@implementation MyClass +@synthesize X = _X; +- (id)initWithY:(id)Y { + self.X = Y; + return self; +} +@end diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m new file mode 100644 index 000000000000..0d699168a551 --- /dev/null +++ b/test/Analysis/ObjCRetSigs.m @@ -0,0 +1,25 @@ +// RUN: clang-cc -analyze -warn-objc-methodsigs -verify %s + +#include + +@interface MyBase +-(long long)length; +@end + +@interface MySub : MyBase{} +-(double)length; +@end + +@implementation MyBase +-(long long)length{ + printf("Called MyBase -length;\n"); + return 3; +} +@end + +@implementation MySub +-(double)length{ // expected-warning{{types are incompatible}} + printf("Called MySub -length;\n"); + return 3.3; +} +@end diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m new file mode 100644 index 000000000000..098bfe8e8539 --- /dev/null +++ b/test/Analysis/PR2599.m @@ -0,0 +1,64 @@ +// RUN: clang-cc -analyze -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s && +// RUN: clang-cc -analyze -analyzer-constraints=range -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s && +// RUN: clang-cc -analyze -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s && +// RUN: clang-cc -analyze -analyzer-constraints=range -analyzer-store=region -checker-cfref -fobjc-gc -verify %s + +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +typedef const struct __CFDictionary * CFDictionaryRef; +CFTypeRef CFMakeCollectable(CFTypeRef cf) ; +extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...); +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)autorelease; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol +NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} +- (id)init; ++ (id)alloc; +@end +enum { NSASCIIStringEncoding = 1, NSNEXTSTEPStringEncoding = 2, NSJapaneseEUCStringEncoding = 3, NSUTF8StringEncoding = 4, NSISOLatin1StringEncoding = 5, NSSymbolStringEncoding = 6, NSNonLossyASCIIStringEncoding = 7, NSShiftJISStringEncoding = 8, NSISOLatin2StringEncoding = 9, NSUnicodeStringEncoding = 10, NSWindowsCP1251StringEncoding = 11, NSWindowsCP1252StringEncoding = 12, NSWindowsCP1253StringEncoding = 13, NSWindowsCP1254StringEncoding = 14, NSWindowsCP1250StringEncoding = 15, NSISO2022JPStringEncoding = 21, NSMacOSRomanStringEncoding = 30, NSUTF16StringEncoding = NSUnicodeStringEncoding, NSUTF16BigEndianStringEncoding = 0x90000100, NSUTF16LittleEndianStringEncoding = 0x94000100, NSUTF32StringEncoding = 0x8c000100, NSUTF32BigEndianStringEncoding = 0x98000100, NSUTF32LittleEndianStringEncoding = 0x9c000100 }; +typedef NSUInteger NSStringEncoding; +@interface NSString : NSObject +- (NSUInteger)length; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer; +@end +@interface NSAutoreleasePool : NSObject {} +- (void)drain; +@end +extern NSString * const NSXMLParserErrorDomain ; + +// The actual test case. UTIL_AUTORELEASE_CF_AS_ID is a macro that doesn't +// actually do what it was intended to. + +#define NSSTRINGWRAPPER(bytes,len) \ + [[[NSString alloc] initWithBytesNoCopy: (void*)(bytes) length: (len) encoding: NSUTF8StringEncoding freeWhenDone: (BOOL)0] autorelease] + +#define UTIL_AUTORELEASE_CF_AS_ID(cf) ( (((void*)0) == (cf)) ? ((void*)0) : [(id) CFMakeCollectable( (CFTypeRef) cf) autorelease] ) + +#define UTIL_AUTORELEASE_CF_AS_ID_WITHOUT_TEST(cf) ( [(id) CFMakeCollectable( (CFTypeRef) cf) autorelease] ) + +static char *lorem = "fooBarBaz"; + +int main (int argc, const char * argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSString *tmp1 = NSSTRINGWRAPPER(lorem, 6); // no-warning + NSString *tmp2 = UTIL_AUTORELEASE_CF_AS_ID( CFStringCreateWithFormat(((void*)0), ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "lorem: %@" "")), tmp1) ); // expected-warning 2 {{leak}} + NSString *tmp3 = UTIL_AUTORELEASE_CF_AS_ID_WITHOUT_TEST( CFStringCreateWithFormat(((void*)0), ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "lorem: %@" "")), tmp1) ); + NSLog(@"tmp2: %@ tmp3: %@", tmp2, tmp3); + [pool drain]; + return 0; +} diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m new file mode 100644 index 000000000000..7bc90b8d03e0 --- /dev/null +++ b/test/Analysis/PR2978.m @@ -0,0 +1,61 @@ +// RUN: clang-cc -analyze -warn-objc-missing-dealloc %s -verify + +// Tests for the checker which checks missing/extra ivar 'release' calls +// in dealloc. + +@interface NSObject +- (void)release; +- dealloc; +@end + +@interface MyClass : NSObject { +@private + id _X; + id _Y; + id _Z; + id _K; + id _N; + id _M; + id _V; + id _W; +} +@property(retain) id X; +@property(retain) id Y; +@property(assign) id Z; +@property(assign) id K; +@property(readonly) id N; +@property(retain) id M; +@property(retain) id V; +@property(retain) id W; +-(id) O; +-(void) setO: (id) arg; +@end + +@implementation MyClass +@synthesize X = _X; +@synthesize Y = _Y; // expected-warning{{The '_Y' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}} +@synthesize Z = _Z; // expected-warning{{The '_Z' instance variable was not retained by a synthesized property but was released in 'dealloc'}} +@synthesize K = _K; +@synthesize N = _N; +@synthesize M = _M; +@synthesize V = _V; +@synthesize W = _W; // expected-warning{{The '_W' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}} + +-(id) O{ return 0; } +-(void) setO:(id)arg { } + +- (id)dealloc +{ + [_X release]; + [_Z release]; + [_N release]; + + self.M = 0; // This will release '_M' + [self setV:0]; // This will release '_V' + [self setW:@"newW"]; // This will release '_W', but retain the new value + self.O = 0; // no-warning + [super dealloc]; +} + +@end + diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m new file mode 100644 index 000000000000..20d4b5b96059 --- /dev/null +++ b/test/Analysis/PR3991.m @@ -0,0 +1,67 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s + +//===----------------------------------------------------------------------===// +// Delta-debugging produced forward declarations. +//===----------------------------------------------------------------------===// + +typedef signed char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} +@end extern id NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone); +@interface NSArray : NSObject - (unsigned)count; +@end @class NSTimer, NSPort, NSArray; +@class NSURLHandle, NSMutableArray, NSMutableData, NSData, NSURL; +@interface NSResponder : NSObject { +} +@end @class NSBitmapImageRep, NSCursor, NSGraphicsContext, NSImage, NSPasteboard, NSScrollView, NSWindow, NSAttributedString; +@interface NSView : NSResponder { + struct __VFlags2 { + } + _vFlags2; +} +@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError; +@interface NSBox : NSView { +} +@end @class GDataFeedDocList, GDataServiceTicket, GDataServiceTicket, IHGoogleDocsAdapter; +@protocol IHGoogleDocsAdapterDelegate - (void)googleDocsAdapter:(IHGoogleDocsAdapter*)inGoogleDocsAdapter accountVerifyIsValid:(BOOL)inIsValid error:(NSError *)inError; +@end @interface IHGoogleDocsAdapter : NSObject { +} +- (NSArray *)entries; +@end extern Class const kGDataUseRegisteredClass ; +@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList; +- (NSArray *)directoryPathComponents; +- (unsigned int)currentPathComponentIndex; +- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex; +- (NSURL *)folderFeedURL; +@end @implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject *)owner { +} + +//===----------------------------------------------------------------------===// +// Actual test case: +// +// The analyzer currently doesn't reason about ObjCKVCRefExpr. Have both +// GRExprEngine::Visit and GRExprEngine::VisitLValue have such expressions +// evaluate to UnknownVal. +//===----------------------------------------------------------------------===// + +- (void)docListListFetchTicket:(GDataServiceTicket *)ticket finishedWithFeed:(GDataFeedDocList *)feed { + BOOL doGetDir = self.directoryPathComponents != 0 && self.currentPathComponentIndex < [self.directoryPathComponents count]; + if (doGetDir) { + BOOL isDirExisting = [[self.feedDocList entries] count] > 0; + if (isDirExisting) { + if (self.folderFeedURL != 0) { + if (++self.currentPathComponentIndex == [self.directoryPathComponents count]) { + } + } + } + } +} diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c new file mode 100644 index 000000000000..c0e1d8b7e39f --- /dev/null +++ b/test/Analysis/array-struct.c @@ -0,0 +1,150 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s + +// RegionStore now has an infinite recursion with this test case. +// NOWORK: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// NOWORK: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +struct s { + int data; + int data_array[10]; +}; + +typedef struct { + int data; +} STYPE; + +void g(char *p); +void g1(struct s* p); + +// Array to pointer conversion. Array in the struct field. +void f(void) { + int a[10]; + int (*p)[10]; + p = &a; + (*p)[3] = 1; + + struct s d; + struct s *q; + q = &d; + q->data = 3; + d.data_array[9] = 17; +} + +// StringLiteral in lvalue context and pointer to array type. +// p: ElementRegion, q: StringRegion +void f2() { + char *p = "/usr/local"; + char (*q)[4]; + q = &"abc"; +} + +// Typedef'ed struct definition. +void f3() { + STYPE s; +} + +// Initialize array with InitExprList. +void f4() { + int a[] = { 1, 2, 3}; + int b[3] = { 1, 2 }; + struct s c[] = {{1,{1}}}; +} + +// Struct variable in lvalue context. +// Assign UnknownVal to the whole struct. +void f5() { + struct s data; + g1(&data); +} + +// AllocaRegion test. +void f6() { + char *p; + p = __builtin_alloca(10); + g(p); + char c = *p; + p[1] = 'a'; + // Test if RegionStore::EvalBinOp converts the alloca region to element + // region. + p += 2; +} + +struct s2; + +void g2(struct s2 *p); + +// Incomplete struct pointer used as function argument. +void f7() { + struct s2 *p = __builtin_alloca(10); + g2(p); +} + +// sizeof() is unsigned while -1 is signed in array index. +void f8() { + int a[10]; + a[sizeof(a)/sizeof(int) - 1] = 1; // no-warning +} + +// Initialization of struct array elements. +void f9() { + struct s a[10]; +} + +// Initializing array with string literal. +void f10() { + char a1[4] = "abc"; + char a3[6] = "abc"; +} + +// Retrieve the default value of element/field region. +void f11() { + struct s a; + g1(&a); + if (a.data == 0) // no-warning + a.data = 1; +} + +// Convert unsigned offset to signed when creating ElementRegion from +// SymbolicRegion. +void f12(int *list) { + unsigned i = 0; + list[i] = 1; +} + +struct s1 { + struct s2 { + int d; + } e; +}; + +// The binding of a.e.d should not be removed. Test recursive subregion map +// building: a->e, e->d. Only then 'a' could be added to live region roots. +void f13(double timeout) { + struct s1 a; + a.e.d = (long) timeout; + if (a.e.d == 10) + a.e.d = 4; +} + +struct s3 { + int a[2]; +}; + +static struct s3 opt; + +// Test if the embedded array is retrieved correctly. +void f14() { + struct s3 my_opt = opt; +} + +void bar(int*); + +// Test if the array is correctly invalidated. +void f15() { + int a[10]; + bar(a); + if (a[1]) // no-warning + 1; +} diff --git a/test/Analysis/basicstore_wine_crash.c b/test/Analysis/basicstore_wine_crash.c new file mode 100644 index 000000000000..cb5fac8d2919 --- /dev/null +++ b/test/Analysis/basicstore_wine_crash.c @@ -0,0 +1,11 @@ +// RUN: clang-cc -checker-cfref -analyze -analyzer-store=basic %s + +// Once xfail_regionstore_wine_crash.c passes, move this test case +// into misc-ps.m. + +void foo() { + long x = 0; + char *y = (char *) &x; + if (!*y) + return; +} diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c new file mode 100644 index 000000000000..94a1eac0a316 --- /dev/null +++ b/test/Analysis/casts.c @@ -0,0 +1,16 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region --verify %s + +// Test if the 'storage' region gets properly initialized after it is cast to +// 'struct sockaddr *'. + +#include +void f(int sock) { + struct sockaddr_storage storage; + struct sockaddr* sockaddr = (struct sockaddr*)&storage; + socklen_t addrlen = sizeof(storage); + getsockname(sock, sockaddr, &addrlen); + switch (sockaddr->sa_family) { // no-warning + default: + ; + } +} diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m new file mode 100644 index 000000000000..82c29fac904f --- /dev/null +++ b/test/Analysis/casts.m @@ -0,0 +1,22 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic --verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region --verify %s + +// Test function pointer casts. Currently we track function addresses using +// loc::FunctionVal. Because casts can be arbitrary, do we need to model +// functions with regions? +typedef void* (*MyFuncTest1)(void); + +MyFuncTest1 test1_aux(void); +void test1(void) { + void *x; + void* (*p)(void); + p = ((void*) test1_aux()); + if (p != ((void*) 0)) x = (*p)(); +} + +// Test casts from void* to function pointers. Same issue as above: +// should we eventually model function pointers using regions? +void* test2(void *p) { + MyFuncTest1 fp = (MyFuncTest1) p; + return (*fp)(); +} diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c new file mode 100644 index 000000000000..695123b53345 --- /dev/null +++ b/test/Analysis/cfref_PR2519.c @@ -0,0 +1,48 @@ +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range -verify %s + +typedef unsigned char Boolean; +typedef signed long CFIndex; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +typedef struct {} CFAllocatorContext; +extern void CFRelease(CFTypeRef cf); +typedef struct {} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct {} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +extern CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +enum { kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 }; +typedef CFIndex CFNumberType; +typedef const struct __CFNumber * CFNumberRef; +extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); +typedef struct __CFNotificationCenter * CFNotificationCenterRef; +extern CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); +extern void CFNotificationCenterPostNotification(CFNotificationCenterRef center, CFStringRef name, const void *object, CFDictionaryRef userInfo, Boolean deliverImmediately); + +// This test case was reported in PR2519 as a false positive (_value was +// reported as being leaked). + +int main(int argc, char **argv) { + CFStringRef _key = ((CFStringRef) __builtin___CFStringMakeConstantString ("" "Process identifier" "")); + int pid = 42; + + CFNumberRef _value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid); + CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&_key, (const void **)&_value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFRelease(_value); // no-warning + CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), + ((CFStringRef) __builtin___CFStringMakeConstantString ("" "GrowlPreferencesChanged" "")), + ((CFStringRef) __builtin___CFStringMakeConstantString ("" "GrowlUserDefaults" "")), + userInfo, 0); + CFRelease(userInfo); // no-warning + + return 0; +} + diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c new file mode 100644 index 000000000000..5d957615d0dd --- /dev/null +++ b/test/Analysis/cfref_rdar6080742.c @@ -0,0 +1,58 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +// This test case was reported in . +// It tests path-sensitivity with respect to '!(cfstring != 0)' (negation of inequality). + +int printf(const char *restrict,...); +typedef unsigned long UInt32; +typedef signed long SInt32; +typedef SInt32 OSStatus; +typedef unsigned char Boolean; +enum { noErr = 0}; +typedef const void *CFTypeRef; +typedef const struct __CFString *CFStringRef; +typedef const struct __CFAllocator *CFAllocatorRef; +extern void CFRelease(CFTypeRef cf); +typedef UInt32 CFStringEncoding; +enum { kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, + kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, + kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, + kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF, + kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, + kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, + kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100}; +extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); + +enum { memROZWarn = -99, memROZError = -99, memROZErr = -99, memFullErr = -108, + nilHandleErr = -109, memWZErr = -111, memPurErr = -112, memAdrErr = -110, + memAZErr = -113, memPCErr = -114, memBCErr = -115, memSCErr = -116, memLockedErr = -117}; + +#define DEBUG1 + +void DebugStop(const char *format,...); +void DebugTraceIf(unsigned int condition, const char *format,...); +Boolean DebugDisplayOSStatusMsg(OSStatus status, const char *statusStr, const char *fileName, unsigned long lineNumber); + +#define Assert(condition)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); } +#define AssertMsg(condition, message)if (!(condition)) { DebugStop("Assertion failure: %s (%s) [File: %s, Line: %lu]", #condition, message, __FILE__, __LINE__); } +#define Require(condition)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); } +#define RequireAction(condition, action)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); action } +#define RequireActionSilent(condition, action)if (!(condition)) { action } +#define AssertNoErr(err){ DebugDisplayOSStatusMsg((err), #err, __FILE__, __LINE__); } +#define RequireNoErr(err, action){ if( DebugDisplayOSStatusMsg((err), #err, __FILE__, __LINE__) ) { action }} + +void DebugStop(const char *format,...); /* Not an abort function. */ + +int main(int argc, char *argv[]) { + CFStringRef cfString; + OSStatus status = noErr; + cfString = CFStringCreateWithCString(0, "hello", kCFStringEncodingUTF8); + RequireAction(cfString != 0, return memFullErr;) //no - warning + printf("cfstring %p\n", cfString); +Exit: + CFRelease(cfString); + return 0; +} diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c new file mode 100644 index 000000000000..f29fc70c4944 --- /dev/null +++ b/test/Analysis/complex.c @@ -0,0 +1,21 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +#include + +int f1(int * p) { + + // This branch should be infeasible + // because __imag__ p is 0. + if (!p && __imag__ (intptr_t) p) + *p = 1; // no-warning + + // If p != 0 then this branch is feasible; otherwise it is not. + if (__real__ (intptr_t) p) + *p = 1; // no-warning + + *p = 2; // expected-warning{{Dereference of null pointer}} +} diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c new file mode 100644 index 000000000000..bebf155f4640 --- /dev/null +++ b/test/Analysis/conditional-op-missing-lhs.c @@ -0,0 +1,26 @@ +// RUN: clang-cc -analyze -warn-dead-stores -warn-uninit-values -verify %s + +void f1() +{ + int i; + + int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' during its initialization is never read}} +} + +void *f2(int *i) +{ + return i ? : 0; +} + +void *f3(int *i) +{ + int a; + + return &a ? : i; +} + +void f4() +{ + char c[1 ? : 2]; +} + diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c new file mode 100644 index 000000000000..c100344adf6d --- /dev/null +++ b/test/Analysis/dead-stores.c @@ -0,0 +1,175 @@ +// RUN: clang-cc -analyze -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s + +void f1() { + int k, y; + int abc=1; + long idx=abc+3*5; // expected-warning {{never read}} +} + +void f2(void *b) { + char *c = (char*)b; // no-warning + char *d = b+1; // expected-warning {{never read}} + printf("%s", c); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \ + // expected-note{{please include the header or explicitly provide a declaration for 'printf'}} +} + +void f3() { + int r; + if ((r = f()) != 0) { // no-warning + int y = r; // no-warning + printf("the error is: %d\n", y); + } +} + +void f4(int k) { + + k = 1; + + if (k) + f1(); + + k = 2; // expected-warning {{never read}} +} + +void f5() { + + int x = 4; // no-warning + int *p = &x; // expected-warning{{never read}} + +} + +int f6() { + + int x = 4; + ++x; // expected-warning{{never read}} + return 1; +} + +int f7(int *p) { + // This is allowed for defensive programming. + p = 0; // no-warning + return 1; +} + +int f8(int *p) { + extern int *baz(); + if (p = baz()) // expected-warning{{Although the value}} + return 1; + return 0; +} + +int f9() { + int x = 4; + x = x + 10; // expected-warning{{never read}} + return 1; +} + +int f10() { + int x = 4; + x = 10 + x; // expected-warning{{never read}} + return 1; +} + +int f11() { + int x = 4; + return x++; // expected-warning{{never read}} +} + +int f11b() { + int x = 4; + return ((((++x)))); // no-warning +} + +int f12a(int y) { + int x = y; // expected-warning{{never read}} + return 1; +} +int f12b(int y) { + int x __attribute__((unused)) = y; // no-warning + return 1; +} + +// Filed with PR 2630. This code should produce no warnings. +int f13(void) +{ + int a = 1; + int b, c = b = a + a; + + if (b > 0) + return (0); + + return (a + b + c); +} + +// Filed with PR 2763. +int f14(int count) { + int index, nextLineIndex; + for (index = 0; index < count; index = nextLineIndex+1) { + nextLineIndex = index+1; // no-warning + continue; + } + return index; +} + +// Test case for +void f15(unsigned x, unsigned y) { + int count = x * y; // no-warning + int z[count]; +} + +int f16(int x) { + x = x * 2; + x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{Although the value stored to 'x' is used}} + ? 5 : 8; + return x; +} + +// Self-assignments should not be flagged as dead stores. +int f17() { + int x = 1; + x = x; // no-warning +} + +// +// The values of dead stores are only "consumed" in an enclosing expression +// what that value is actually used. In other words, don't say "Although the value stored to 'x' is used...". +int f18() { + int x = 0; // no-warning + if (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} + while (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} + do + x = 10; // expected-warning{{Value stored to 'x' is never read}} + while (1); + + return (x = 10); // expected-warning{{Although the value stored to 'x' is used in the enclosing expression, the value is never actually read from 'x'}} +} + +// PR 3514: false positive `dead initialization` warning for init to global +// http://llvm.org/bugs/show_bug.cgi?id=3514 +extern const int MyConstant; +int f19(void) { + int x = MyConstant; // no-warning + x = 1; + return x; +} + +int f19b(void) { // This case is the same as f19. + const int MyConstant = 0; + int x = MyConstant; // no-warning + x = 1; + return x; +} + +void f20(void) { + int x = 1; // no-warning +#pragma unused(x) +} + diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m new file mode 100644 index 000000000000..218cb4458580 --- /dev/null +++ b/test/Analysis/dead-stores.m @@ -0,0 +1,36 @@ +// RUN: clang-cc -analyze -warn-dead-stores -verify %s + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSValue : NSObject - (void)getValue:(void *)value; @end +typedef float CGFloat; +typedef struct _NSPoint {} NSRange; +@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range; +- (BOOL)containsObject:(id)anObject; +@end +@class NSURLAuthenticationChallenge; +@interface NSResponder : NSObject {} @end +@class NSArray, NSDictionary, NSString; +@interface NSObject (NSKeyValueBindingCreation) ++ (void)exposeBinding:(NSString *)binding; +- (NSArray *)exposedBindings; +@end +extern NSString *NSAlignmentBinding; + +// This test case was reported as a false positive due to a bug in the +// LiveVariables <-> DeadStores interplay. We should not flag a warning +// here. The test case was reported in: +// http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-July/002157.html +void DeadStoreTest(NSObject *anObject) { + NSArray *keys; + if ((keys = [anObject exposedBindings]) && // no-warning + ([keys containsObject:@"name"] && [keys containsObject:@"icon"])) {} +} + diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m new file mode 100644 index 000000000000..440f31113cff --- /dev/null +++ b/test/Analysis/delegates.m @@ -0,0 +1,114 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not directly including Foundation.h directly makes this test case +// both svelte and portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern CFTypeRef CFRetain(CFTypeRef cf); +void CFRelease(CFTypeRef cf); +typedef const struct __CFDictionary * CFDictionaryRef; +const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key); +extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...); +typedef signed char BOOL; +typedef int NSInteger; +typedef unsigned int NSUInteger; +typedef struct objc_selector *SEL; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef NSInteger NSComparisonResult; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (oneway void)release; +- (Class)class; +- (id)retain; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} +- (id)init; ++ (id)alloc; ++ (Class)class; +- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; +@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; +typedef struct _NSRange {} NSRange; +@interface NSArray : NSObject +- (NSUInteger)count; +@end +@interface NSMutableArray : NSArray +- (void)addObject:(id)anObject; +- (id)initWithCapacity:(NSUInteger)numItems; +@end +typedef unsigned short unichar; +@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale; +typedef NSUInteger NSStringCompareOptions; +@interface NSString : NSObject - (NSUInteger)length; +- (NSComparisonResult)compare:(NSString *)string; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange; +- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale; +- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string; +- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator; +@end +@interface NSSimpleCString : NSString {} @end +@interface NSConstantString : NSSimpleCString @end +extern void *_NSConstantStringClassReference; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +// +// The analyzer doesn't perform any inter-procedural analysis, so delegates +// involving [NSObject performSelector...] tend to lead to false positives. +// For now the analyzer just stops tracking the reference count of the +// receiver until we have better support for delegates. + +@interface test_6062730 : NSObject ++ (void)postNotification:(NSString *)str; +- (void)foo; +- (void)bar; +@end + +@implementation test_6062730 +- (void) foo { + NSString *str = [[NSString alloc] init]; + [test_6062730 performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1]; +} + +- (void) bar { + NSString *str = [[NSString alloc] init]; // expected-warning{{leak}} + // FIXME: We need to resolve [self class] to 'test_6062730'. + [[self class] performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1]; +} + ++ (void) postNotification:(NSString *)str { + [str release]; // no-warning +} +@end + diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c new file mode 100644 index 000000000000..08842b1b8dbf --- /dev/null +++ b/test/Analysis/exercise-ps.c @@ -0,0 +1,25 @@ +// RUN: clang-cc -analyze -checker-simple -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// +// Just exercise the analyzer on code that has at one point caused issues +// (i.e., no assertions or crashes). + + +static const char * f1(const char *x, char *y) { + while (*x != 0) { + *y++ = *x++; + } +} + +// This following case checks that we properly handle typedefs when getting +// the RvalueType of an ElementRegion. +typedef struct F12_struct {} F12_typedef; +typedef void* void_typedef; +void_typedef f2_helper(); +static void f2(void *buf) { + F12_typedef* x; + x = f2_helper(); + memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring C library function 'memcpy' with type 'void *(void *, void const *}} \ + // expected-note{{please include the header or explicitly provide a declaration for 'memcpy'}} +} diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c new file mode 100644 index 000000000000..c012a9da7b81 --- /dev/null +++ b/test/Analysis/fields.c @@ -0,0 +1,10 @@ +// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=basic -verify && +// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=region -verify + +unsigned foo(); +typedef struct bf { unsigned x:2; } bf; +void bar() { + bf y; + *(unsigned*)&y = foo(); + y.x = 1; +} diff --git a/test/Analysis/func.c b/test/Analysis/func.c new file mode 100644 index 000000000000..ac067a98103c --- /dev/null +++ b/test/Analysis/func.c @@ -0,0 +1,17 @@ +// RUN: clang-cc -analyze -checker-simple -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +void f(void) { + void (*p)(void); + p = f; + p = &f; + p(); + (*p)(); +} + +void g(void (*fp)(void)); + +void f2() { + g(f); +} diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m new file mode 100644 index 000000000000..163da4b4abeb --- /dev/null +++ b/test/Analysis/misc-ps-64.m @@ -0,0 +1,49 @@ +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s && +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s && +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s && +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s + +// - A bunch of misc. failures involving evaluating +// these expressions and building CFGs. These tests are here to prevent +// regressions. +typedef long long int64_t; +@class NSString, NSDictionary; +typedef long NSInteger; +typedef unsigned long NSUInteger; +typedef unsigned char Boolean; +typedef const struct __CFDictionary * CFDictionaryRef; + +extern Boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, const void *key, const void **value); +static void shazam(NSUInteger i, unsigned char **out); + +void rdar_6440393_1(NSDictionary *dict) { + NSInteger x = 0; + unsigned char buf[10], *bufptr = buf; + if (!CFDictionaryGetValueIfPresent(0, dict, (void *)&x)) + return; + shazam(x, &bufptr); +} + +// - In this example we got a signedness +// mismatch between the literal '0' and the value of 'scrooge'. The +// trick is to have the evaluator convert the literal to an unsigned +// integer when doing a comparison with the pointer. This happens +// because of the transfer function logic of +// OSAtomicCompareAndSwap64Barrier, which doesn't have special casts +// in place to do this for us. +_Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ); +extern id objc_lookUpClass(const char *name); +void rdar_6845148(id debug_yourself) { + if (!debug_yourself) { + const char *wacky = ((void *)0); + Class scrooge = wacky ? (Class)objc_lookUpClass(wacky) : ((void *)0); + OSAtomicCompareAndSwap64Barrier(0, (int64_t)scrooge, (int64_t*)&debug_yourself); + } +} +void rdar_6845148_b(id debug_yourself) { + if (!debug_yourself) { + const char *wacky = ((void *)0); + Class scrooge = wacky ? (Class)objc_lookUpClass(wacky) : ((void *)0); + OSAtomicCompareAndSwap64Barrier((int64_t)scrooge, 0, (int64_t*)&debug_yourself); + } +} diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m new file mode 100644 index 000000000000..1207f8663e90 --- /dev/null +++ b/test/Analysis/misc-ps-basic-store.m @@ -0,0 +1,21 @@ +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic --verify -fblocks %s + +//--------------------------------------------------------------------------- +// Test case 'checkaccess_union' differs for region store and basic store. +// The basic store doesn't reason about compound literals, so the code +// below won't fire an "uninitialized value" warning. +//--------------------------------------------------------------------------- + +// PR 2948 (testcase; crash on VisitLValue for union types) +// http://llvm.org/bugs/show_bug.cgi?id=2948 + +void checkaccess_union() { + int ret = 0, status; + if (((((__extension__ (((union { // no-warning + __typeof (status) __in; int __i;} + ) + { + .__in = (status)} + ).__i))) & 0xff00) >> 8) == 1) + ret = 1; +} diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m new file mode 100644 index 000000000000..818922eba925 --- /dev/null +++ b/test/Analysis/misc-ps-eager-assume.m @@ -0,0 +1,79 @@ +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s -analyzer-eagerly-assume + +// Delta-reduced header stuff (needed for test cases). +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +- (oneway void)release; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject {} ++ (id)alloc; +@end typedef struct {} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @interface NSArray : NSObject - (NSUInteger)count; +@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; +- (BOOL)isEqualToString:(NSString *)aString; +@end @interface NSAutoreleasePool : NSObject {} +- (void)drain; +- (id)init; +@end + +// This test case tests that (x != 0) is eagerly evaluated before stored to +// 'y'. This test case complements recoverCastedSymbol (see below) because +// the symbolic expression is stored to 'y' (which is a short instead of an +// int). recoverCastedSymbol() only recovers path-sensitivity when the +// symbolic expression is literally the branch condition. +// +void handle_assign_of_condition(int x) { + // The cast to 'short' causes us to lose symbolic constraint. + short y = (x != 0); + char *p = 0; + if (y) { + // This should be infeasible. + if (!(x != 0)) { + *p = 1; // no-warning + } + } +} + +// From +// +// In this test case, 'needsAnArray' is a signed char. The analyzer tracks +// a symbolic value for this variable, but in the branch condition it is +// promoted to 'int'. Currently the analyzer doesn't reason well about +// promotions of symbolic values, so this test case tests the logic in +// 'recoverCastedSymbol()' (GRExprEngine.cpp) to test that we recover +// path-sensitivity and use the symbol for 'needsAnArray' in the branch +// condition. +// +void handle_symbolic_cast_in_condition(void) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + BOOL needsAnArray = [@"aString" isEqualToString:@"anotherString"]; + NSMutableArray* array = needsAnArray ? [[NSMutableArray alloc] init] : 0; + if(needsAnArray) + [array release]; + + [pool drain]; +} + +// From PR 3836 (http://llvm.org/bugs/show_bug.cgi?id=3836) +// +// In this test case, the double '!' works fine with our symbolic constraints, +// but we don't support comparing SymConstraint != SymConstraint. By eagerly +// assuming the truth of !!a or !!b, we can compare these values directly. +// +void pr3836(int *a, int *b) { + if (!!a != !!b) /* one of them is NULL */ + return; + if (!a && !b) /* both are NULL */ + return; + + *a = 1; // no-warning + *b = 1; // no-warning +} diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m new file mode 100644 index 000000000000..a191bec3cfb1 --- /dev/null +++ b/test/Analysis/misc-ps-ranges.m @@ -0,0 +1,23 @@ +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s && +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s + +// +// main's 'argc' argument is always > 0 +int main(int argc, char* argv[]) { + int *p = 0; + + if (argc == 0) + *p = 1; + + if (argc == 1) + return 1; + + int x = 1; + int i; + + for(i=1;i {} - (id)init; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject +- (NSUInteger)length; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end extern NSString * const NSBundleDidLoadNotification; +@interface NSAssertionHandler : NSObject {} ++ (NSAssertionHandler *)currentHandler; +- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...; +@end +extern NSString * const NSConnectionReplyMode; + + +//--------------------------------------------------------------------------- +// Test case 'checkaccess_union' differs for region store and basic store. +// The basic store doesn't reason about compound literals, so the code +// below won't fire an "uninitialized value" warning. +//--------------------------------------------------------------------------- + +// PR 2948 (testcase; crash on VisitLValue for union types) +// http://llvm.org/bugs/show_bug.cgi?id=2948 + +void checkaccess_union() { + int ret = 0, status; + if (((((__extension__ (((union { // expected-warning {{ Branch condition evaluates to an uninitialized value.}} + __typeof (status) __in; int __i;} + ) + { + .__in = (status)} + ).__i))) & 0xff00) >> 8) == 1) + ret = 1; +} + + +// Check our handling of fields being invalidated by function calls. +struct test2_struct { int x; int y; char* s; }; +void test2_helper(struct test2_struct* p); + +char test2() { + struct test2_struct s; + test2_help(&s); + char *p = 0; + + if (s.x > 1) { + if (s.s != 0) { + p = "hello"; + } + } + + if (s.x > 1) { + if (s.s != 0) { + return *p; + } + } + + return 'a'; +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m new file mode 100644 index 000000000000..205bac2c825f --- /dev/null +++ b/test/Analysis/misc-ps.m @@ -0,0 +1,287 @@ +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s && +// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s + +// NOWORK: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s && +// NOWORK: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s + +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef int NSInteger; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} - (id)init; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject +- (NSUInteger)length; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end extern NSString * const NSBundleDidLoadNotification; +@interface NSAssertionHandler : NSObject {} ++ (NSAssertionHandler *)currentHandler; +- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...; +@end +extern NSString * const NSConnectionReplyMode; +typedef float CGFloat; +typedef struct _NSPoint { + CGFloat x; + CGFloat y; +} NSPoint; +typedef struct _NSSize { + CGFloat width; + CGFloat height; +} NSSize; +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +// Reduced test case from crash in +@interface A @end +@implementation A +- (void)foo:(void (^)(NSObject *x))block { + if (!((block != ((void *)0)))) {} +} +@end + +// Reduced test case from crash in PR 2796; +// http://llvm.org/bugs/show_bug.cgi?id=2796 + +unsigned foo(unsigned x) { return __alignof__((x)) + sizeof(x); } + +// Improvement to path-sensitivity involving compound assignments. +// Addresses false positive in +// + +unsigned r6268365Aux(); + +void r6268365() { + unsigned x = 0; + x &= r6268365Aux(); + unsigned j = 0; + + if (x == 0) ++j; + if (x == 0) x = x / j; // no-warning +} + +void divzeroassume(unsigned x, unsigned j) { + x /= j; + if (j == 0) x /= 0; // no-warning + if (j == 0) x /= j; // no-warning + if (j == 0) x = x / 0; // no-warning +} + +void divzeroassumeB(unsigned x, unsigned j) { + x = x / j; + if (j == 0) x /= 0; // no-warning + if (j == 0) x /= j; // no-warning + if (j == 0) x = x / 0; // no-warning +} + +// InitListExpr processing + +typedef float __m128 __attribute__((__vector_size__(16), __may_alias__)); +__m128 return128() { + // This compound literal has a Vector type. We currently just + // return UnknownVal. + return __extension__(__m128) { 0.0f, 0.0f, 0.0f, 0.0f }; +} + +typedef long long __v2di __attribute__ ((__vector_size__ (16))); +typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__)); +__m128i vec128i(long long __q1, long long __q0) { + // This compound literal returns true for both isVectorType() and + // isIntegerType(). + return __extension__ (__m128i)(__v2di){ __q0, __q1 }; +} + +// Zero-sized VLAs. +void check_zero_sized_VLA(int x) { + if (x) + return; + + int vla[x]; // expected-warning{{Variable-length array 'vla' has zero elements (undefined behavior)}} +} + +void check_uninit_sized_VLA() { + int x; + int vla[x]; // expected-warning{{Variable-length array 'vla' garbage value for array size}} +} + +// sizeof(void) +// - Tests a regression reported in PR 3211: http://llvm.org/bugs/show_bug.cgi?id=3211 +void handle_sizeof_void(unsigned flag) { + int* p = 0; + + if (flag) { + if (sizeof(void) == 1) + return; + // Infeasible. + *p = 1; // no-warning + } + + void* q; + + if (!flag) { + if (sizeof(*q) == 1) + return; + // Infeasibe. + *p = 1; // no-warning + } + + // Infeasible. + *p = 1; // no-warning +} + +// PR 3422 +void pr3422_helper(char *p); +void pr3422() { + char buf[100]; + char *q = &buf[10]; + pr3422_helper(&q[1]); +} + +// PR 3543 (handle empty statement expressions) +int pr_3543(void) { + ({}); +} + +// +// This test case test the use of a vector type within an array subscript +// expression. +typedef long long __a64vector __attribute__((__vector_size__(8))); +typedef long long __a128vector __attribute__((__vector_size__(16))); +static inline __a64vector __attribute__((__always_inline__, __nodebug__)) +my_test_mm_movepi64_pi64(__a128vector a) { + return (__a64vector)a[0]; +} + +// Test basic tracking of ivars associated with 'self'. +@interface SelfIvarTest : NSObject { + int flag; +} +- (void)test_self_tracking; +@end + +@implementation SelfIvarTest +- (void)test_self_tracking { + char *p = 0; + char c; + + if (flag) + p = "hello"; + + if (flag) + c = *p; // no-warning +} +@end + +// PR 3770 +char pr3770(int x) { + int y = x & 0x2; + char *p = 0; + if (y == 1) + p = "hello"; + + if (y == 1) + return p[0]; // no-warning + + return 'a'; +} + +// PR 3772 +// - We just want to test that this doesn't crash the analyzer. +typedef struct st ST; +struct st { char *name; }; +extern ST *Cur_Pu; + +void pr3772(void) +{ + static ST *last_Cur_Pu; + if (last_Cur_Pu == Cur_Pu) { + return; + } +} + +// PR 3780 - This tests that StmtIterator isn't broken for VLAs in DeclGroups. +void pr3780(int sz) { typedef double MAT[sz][sz]; } + +// - Test that we don't symbolicate doubles before +// we are ready to do something with them. +int rdar6695527(double x) { + if (!x) { return 0; } + return 1; +} + +// - Test that we properly invalidate structs +// passed-by-reference to a function. +void pr6708148_invalidate(NSRect *x); +void pr6708148_use(NSRect x); +void pr6708148_test(void) { + NSRect x; + pr6708148_invalidate(&x); + pr6708148_use(x); // no-warning +} + +// Handle both kinds of noreturn attributes for pruning paths. +void rdar_6777003_noret() __attribute__((noreturn)); +void rdar_6777003_analyzer_noret() __attribute__((analyzer_noreturn)); + +void rdar_6777003(int x) { + int *p = 0; + + if (x == 1) { + rdar_6777003_noret(); + *p = 1; // no-warning; + } + + if (x == 2) { + rdar_6777003_analyzer_noret(); + *p = 1; // no-warning; + } + + *p = 1; // expected-warning{{Dereference of null pointer}} +} + +// For pointer arithmetic, --/++ should be treated as preserving non-nullness, +// regardless of how well the underlying StoreManager reasons about pointer +// arithmetic. +// +void rdar_6777209(char *p) { + if (p == 0) + return; + + ++p; + + // This branch should always be infeasible. + if (p == 0) + *p = 'c'; // no-warning +} + +// PR 4033. A symbolic 'void *' pointer can be used as the address for a +// computed goto. +typedef void *Opcode; +Opcode pr_4033_getOpcode(); +void pr_4033(void) { +next_opcode: + { + Opcode op = pr_4033_getOpcode(); + if (op) goto *op; + } +} + +// Test invalidating pointers-to-pointers with slightly different types. This +// example came from a recent false positive due to a regression where the +// branch condition was falsely reported as being uninitialized. +void invalidate_by_ref(char **x); +int test_invalidate_by_ref() { + unsigned short y; + invalidate_by_ref((char**) &y); + if (y) // no-warning + return 1; + return 0; +} + diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m new file mode 100644 index 000000000000..9a64b3001e16 --- /dev/null +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -0,0 +1,67 @@ +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify + +@interface MyClass {} +- (void *)voidPtrM; +- (int)intM; +- (long long)longlongM; +- (double)doubleM; +- (long double)longDoubleM; +- (void)voidM; +@end +@implementation MyClass +- (void *)voidPtrM { return (void *)0; } +- (int)intM { return 0; } +- (long long)longlongM { return 0; } +- (double)doubleM { return 0.0; } +- (long double)longDoubleM { return 0.0; } +- (void)voidM {} +@end + +void createFoo() { + MyClass *obj = 0; + + void *v = [obj voidPtrM]; // no-warning + int i = [obj intM]; // no-warning +} + +void createFoo2() { + MyClass *obj = 0; + + long double ld = [obj longDoubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo3() { + MyClass *obj; + obj = 0; + + long long ll = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo4() { + MyClass *obj = 0; + + double d = [obj doubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo5() { + MyClass *obj = @""; + + double d = [obj doubleM]; // no-warning +} + +void handleNilPruneLoop(MyClass *obj) { + if (!!obj) + return; + + // Test if [obj intM] evaluates to 0, thus pruning the entire loop. + for (int i = 0; i < [obj intM]; i++) { + long long j = [obj longlongM]; // no-warning + } + + long long j = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +int handleVoidInComma() { + MyClass *obj = 0; + return [obj voidM], 0; +} diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c new file mode 100644 index 000000000000..cad2127b2082 --- /dev/null +++ b/test/Analysis/no-exit-cfg.c @@ -0,0 +1,19 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +// This is a test case for the issue reported in PR 2819: +// http://llvm.org/bugs/show_bug.cgi?id=2819 +// The flow-sensitive dataflow solver should work even when no block in +// the CFG reaches the exit block. + +int g(int x); +void h(int x); + +int f(int x) +{ +out_err: + if (g(x)) { + h(x); + } + goto out_err; +} diff --git a/test/Analysis/no-outofbounds-basicstore.c b/test/Analysis/no-outofbounds-basicstore.c new file mode 100644 index 000000000000..9a0b35906d7c --- /dev/null +++ b/test/Analysis/no-outofbounds-basicstore.c @@ -0,0 +1,7 @@ +// RUN: clang-cc -checker-cfref -analyze -analyzer-store=basic -verify %s + +void f() { + long x = 0; + char *y = (char*) &x; + char c = y[0] + y[1] + y[2]; // no-warning +} diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c new file mode 100644 index 000000000000..80a5f9212fac --- /dev/null +++ b/test/Analysis/null-deref-ps-region.c @@ -0,0 +1,14 @@ +// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -verify %s + + +// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may +// also be live roots. +void f14(int *a) { + int i; + a[1] = 1; + i = a[1]; + if (i != 1) { + int *p = 0; + i = *p; // no-warning + } +} diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c new file mode 100644 index 000000000000..09b9c2ffa3b7 --- /dev/null +++ b/test/Analysis/null-deref-ps.c @@ -0,0 +1,265 @@ +// RUN: clang-cc -analyze -std=gnu99 -checker-simple -verify %s && +// RUN: clang-cc -analyze -std=gnu99 -checker-simple -verify %s -analyzer-constraints=range && +// RUN: clang-cc -analyze -std=gnu99 -checker-simple -analyzer-store=region -analyzer-purge-dead=false -verify %s && +// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -verify %s + +#include +#include + +void f1(int *p) { + if (p) *p = 1; + else *p = 0; // expected-warning{{ereference}} +} + +struct foo_struct { + int x; +}; + +int f2(struct foo_struct* p) { + + if (p) + p->x = 1; + + return p->x++; // expected-warning{{Dereference of null pointer.}} +} + +int f3(char* x) { + + int i = 2; + + if (x) + return x[i - 1]; + + return x[i+1]; // expected-warning{{Dereference of null pointer.}} +} + +int f3_b(char* x) { + + int i = 2; + + if (x) + return x[i - 1]; + + return x[i+1]++; // expected-warning{{Dereference of null pointer.}} +} + +int f4(int *p) { + + uintptr_t x = (uintptr_t) p; + + if (x) + return 1; + + int *q = (int*) x; + return *q; // expected-warning{{Dereference of null pointer.}} +} + +int f4_b() { + short array[2]; + uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion initializing}} + short *p = x; // expected-warning{{incompatible integer to pointer conversion initializing}} + + // The following branch should be infeasible. + if (!(p = &array[0])) { + p = 0; + *p = 1; // no-warning + } + + if (p) { + *p = 5; // no-warning + p = 0; + } + else return; // expected-warning {{non-void function 'f4_b' should return a value}} + + *p += 10; // expected-warning{{Dereference of null pointer}} +} + + +int f5() { + + char *s = "hello world"; + return s[0]; // no-warning +} + +int bar(int* p, int q) __attribute__((nonnull)); + +int f6(int *p) { + return !p ? bar(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}} + : bar(p, 0); // no-warning +} + +int bar2(int* p, int q) __attribute__((nonnull(1))); + +int f6b(int *p) { + return !p ? bar2(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}} + : bar2(p, 0); // no-warning +} + +int bar3(int*p, int q, int *r) __attribute__((nonnull(1,3))); + +int f6c(int *p, int *q) { + return !p ? bar3(q, 2, p) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}} + : bar3(p, 2, q); // no-warning +} + +int* qux(); + +int f7(int x) { + + int* p = 0; + + if (0 == x) + p = qux(); + + if (0 == x) + *p = 1; // no-warning + + return x; +} + +int* f7b(int *x) { + + int* p = 0; + + if (((void*)0) == x) + p = qux(); + + if (((void*)0) == x) + *p = 1; // no-warning + + return x; +} + +int* f7c(int *x) { + + int* p = 0; + + if (((void*)0) == x) + p = qux(); + + if (((void*)0) != x) + return x; + + // If we reach here then 'p' is not null. + *p = 1; // no-warning + return x; +} + +int* f7c2(int *x) { + + int* p = 0; + + if (((void*)0) == x) + p = qux(); + + if (((void*)0) == x) + return x; + + *p = 1; // expected-warning{{null}} + return x; +} + + +int f8(int *p, int *q) { + if (!p) + if (p) + *p = 1; // no-warning + + if (q) + if (!q) + *q = 1; // no-warning +} + +int* qux(); + +int f9(unsigned len) { + assert (len != 0); + int *p = 0; + unsigned i; + + for (i = 0; i < len; ++i) + p = qux(i); + + return *p++; // no-warning +} + +int f9b(unsigned len) { + assert (len > 0); // note use of '>' + int *p = 0; + unsigned i; + + for (i = 0; i < len; ++i) + p = qux(i); + + return *p++; // no-warning +} + +int* f10(int* p, signed char x, int y) { + // This line tests symbolication with compound assignments where the + // LHS and RHS have different bitwidths. The new symbolic value + // for 'x' should have a bitwidth of 8. + x &= y; + + // This tests that our symbolication worked, and that we correctly test + // x against 0 (with the same bitwidth). + if (!x) { + if (!p) return; // expected-warning {{non-void function 'f10' should return a value}} + *p = 10; + } + else p = 0; + + if (!x) + *p = 5; // no-warning + + return p; +} + +// Test case from +void f11(unsigned i) { + int *x = 0; + if (i >= 0) { + // always true + } else { + *x = 42; // no-warning + } +} + +void f11b(unsigned i) { + int *x = 0; + if (i <= ~(unsigned)0) { + // always true + } else { + *x = 42; // no-warning + } +} + +// Test case for switch statements with weird case arms. +typedef int BOOL, *PBOOL, *LPBOOL; +typedef long LONG_PTR, *PLONG_PTR; +typedef unsigned long ULONG_PTR, *PULONG_PTR; +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; +typedef LONG_PTR LRESULT; +typedef struct _F12ITEM *HF12ITEM; + +void f12(HF12ITEM i, char *q) { + char *p = 0; + switch ((DWORD_PTR) i) { + case 0 ... 10: + p = q; + break; + case (DWORD_PTR) ((HF12ITEM) - 65535): + return; + default: + return; + } + + *p = 1; // no-warning +} + +// Test handling of translating between integer "pointers" and back. +void f13() { + int *x = 0; + if (((((int) x) << 2) + 1) >> 1) *x = 1; // no-warning +} + + diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c new file mode 100644 index 000000000000..953075fe03d7 --- /dev/null +++ b/test/Analysis/outofbound.c @@ -0,0 +1,7 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s + +char f1() { + char* s = "abcd"; + char c = s[4]; // no-warning + return s[5] + c; // expected-warning{{Load or store into an out-of-bound memory position.}} +} diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c new file mode 100644 index 000000000000..f928ee031fe3 --- /dev/null +++ b/test/Analysis/override-werror.c @@ -0,0 +1,15 @@ +// RUN: clang-cc -analyze -checker-cfref -Werror %s -analyzer-store=basic -verify && +// RUN: clang-cc -analyze -checker-cfref -Werror %s -analyzer-store=region -verify + +// This test case illustrates that using '-analyze' overrides the effect of +// -Werror. This allows basic warnings not to interfere with producing +// analyzer results. + +char* f(int *p) { + return p; // expected-warning{{incompatible pointer types returning 'int *', expected 'char *'}} +} + +void g(int *p) { + if (!p) *p = 0; // expected-warning{{null}} +} + diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m new file mode 100644 index 000000000000..7d7d8fc5a157 --- /dev/null +++ b/test/Analysis/pr4209.m @@ -0,0 +1,70 @@ +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -verify %s && +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-store=region -verify %s + +// This test case was crashing due to how CFRefCount.cpp resolved the +// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr. + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} +@end typedef float CGFloat; +typedef struct _NSPoint { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString; +@interface NSArray : NSObject - (NSUInteger)count; +@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; +@end typedef unsigned short unichar; +@interface NSString : NSObject - (NSUInteger)length; +- (int)intValue; +@end @interface NSSimpleCString : NSString { +} +@end @interface NSConstantString : NSSimpleCString @end extern void *_NSConstantStringClassReference; +@interface NSDictionary : NSObject - (NSUInteger)count; +@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; +@end typedef struct { +} +CMProfileLocation; +@interface NSResponder : NSObject { +} +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@interface NSCell : NSObject { +} +@end extern NSString *NSControlTintDidChangeNotification; +@interface NSActionCell : NSCell { +} +@end @class NSArray, NSDocument, NSWindow; +@interface NSWindowController : NSResponder { +} +@end @class EBayCategoryType, GSEbayCategory, GBSearchRequest; +@interface GBCategoryChooserPanelController : NSWindowController { + GSEbayCategory *rootCategory; +} +- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; +-(NSString*) categoryID; +@end @interface GSEbayCategory : NSObject { +} +- (int) categoryID; +- (GSEbayCategory *) parent; +- (GSEbayCategory*) subcategoryWithID:(int) inID; +@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { +} +- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories { + GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; + if (rootCategory != category) { + GSEbayCategory *parent = category; + while ((((void*)0) != (parent = [parent parent])) && ([parent categoryID] != 0)) { + NSMutableDictionary *treeCategoryDict = [self categoryDictionaryForCategoryID:[parent categoryID] inRootTreeCategories:inRootTreeCategories]; + if (((void*)0) == treeCategoryDict) { + } + } + } +} diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m new file mode 100644 index 000000000000..82a028d652d1 --- /dev/null +++ b/test/Analysis/pr_2542_rdar_6793404.m @@ -0,0 +1,68 @@ +// RUN: clang-cc -analyze -checker-cfref -pedantic -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -pedantic -analyzer-store=region -verify %s + +// BEGIN delta-debugging reduced header stuff + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSCoder; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} +- (id)init; ++ (id)alloc; +@end +typedef double NSTimeInterval; +enum { NSAnimationEaseInOut, NSAnimationEaseIn, NSAnimationEaseOut, NSAnimationLinear }; +typedef NSUInteger NSAnimationCurve; +@interface NSAnimation : NSObject {} +- (id)initWithDuration:(NSTimeInterval)duration animationCurve:(NSAnimationCurve)animationCurve; +- (void)startAnimation; +- (void)setDelegate:(id)delegate; +@end + +// END delta-debugging reduced header stuff + +// From NSAnimation Class Reference +// -(void)startAnimation +// The receiver retains itself and is then autoreleased at the end +// of the animation or when it receives stopAnimation. + +@interface MyClass { } +- (void)animationDidEnd:(NSAnimation *)animation; +@end + +@implementation MyClass +- (void)f1 { + // NOTE: The analyzer doesn't really handle this; it just stops tracking + // 'animation' when it is sent the message 'setDelegate:'. + NSAnimation *animation = [[NSAnimation alloc] // no-warning + initWithDuration:1.0 + animationCurve:NSAnimationEaseInOut]; + + [animation setDelegate:self]; + [animation startAnimation]; +} + +- (void)f2 { + NSAnimation *animation = [[NSAnimation alloc] // expected-warning{{leak}} + initWithDuration:1.0 + animationCurve:NSAnimationEaseInOut]; + + [animation startAnimation]; +} + +- (void)animationDidEnd:(NSAnimation *)animation { + [animation release]; +} +@end diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c new file mode 100644 index 000000000000..cc2479c3e49c --- /dev/null +++ b/test/Analysis/pr_4164.c @@ -0,0 +1,41 @@ +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref -analyzer-store=region -verify %s + +// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164 +// +// Eventually this should be pulled into misc-ps.m. This is in a separate test +// file for now to play around with the specific issues for BasicStoreManager +// and StoreManager (i.e., we can make a copy of this file for either +// StoreManager should one start to fail in the near future). +// +// The basic issue is that the VarRegion for 'size' is casted to (char*), +// resulting in an ElementRegion. 'getsockopt' is an unknown function that +// takes a void*, which means the ElementRegion should get stripped off. +typedef unsigned int __uint32_t; +typedef __uint32_t __darwin_socklen_t; +typedef __darwin_socklen_t socklen_t; +int getsockopt(int, int, int, void * restrict, socklen_t * restrict); + +int test1() { + int s = -1; + int size; + socklen_t size_len = sizeof(size); + if (getsockopt(s, 0xffff, 0x1001, (char *)&size, &size_len) < 0) + return -1; + + return size; // no-warning +} + +// Similar case: instead of passing a 'void*', we pass 'char*'. In this +// case we pass an ElementRegion to the invalidation logic. Since it is +// an ElementRegion that just layers on top of another typed region and the +// ElementRegion itself has elements whose type are integral (essentially raw +// data) we strip off the ElementRegion when doing the invalidation. +int takes_charptr(char* p); +int test2() { + int size; + if (takes_charptr((char*)&size)) + return -1; + return size; // no-warning +} + diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c new file mode 100644 index 000000000000..ea8b7f566615 --- /dev/null +++ b/test/Analysis/ptr-arith.c @@ -0,0 +1,34 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify -triple i686-apple-darwin9 %s + +void f1() { + int a[10]; + int *p = a; + ++p; +} + +char* foo(); + +void f2() { + char *p = foo(); + ++p; +} + +// This test case checks if we get the right rvalue type of a TypedViewRegion. +// The ElementRegion's type depends on the array region's rvalue type. If it was +// a pointer type, we would get a loc::SymbolVal for '*p'. +char* memchr(); +static int +domain_port (const char *domain_b, const char *domain_e, + const char **domain_e_ptr) +{ + int port = 0; + + const char *p; + const char *colon = memchr (domain_b, ':', domain_e - domain_b); + + for (p = colon + 1; p < domain_e ; p++) + port = 10 * port + (*p - '0'); + return port; +} diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m new file mode 100644 index 000000000000..15d349884093 --- /dev/null +++ b/test/Analysis/rdar-6442306-1.m @@ -0,0 +1,31 @@ +// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=basic -verify && +// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=region -verify + +typedef int bar_return_t; +typedef struct { + unsigned char int_rep; +} Foo_record_t; +extern Foo_record_t Foo_record; +struct QuxSize {}; +typedef struct QuxSize QuxSize; +typedef struct { + Foo_record_t Foo; + QuxSize size; +} __Request__SetPortalSize_t; + +static __inline__ bar_return_t +__Beeble_check__Request__SetPortalSize_t(__attribute__((__unused__)) __Request__SetPortalSize_t *In0P) { + if (In0P->Foo.int_rep != Foo_record.int_rep) { + do { + int __i__, __C__ = (2); + for (__i__ = 0; + __i__ < __C__; + __i__++) do { + *(&((double *)(&In0P->size))[__i__]) = + __Foo_READSWAP__double(&((double *)(&In0P->size))[__i__]); + } + while (0); + } + while (0); + } +} diff --git a/test/Analysis/rdar-6539791.c b/test/Analysis/rdar-6539791.c new file mode 100644 index 000000000000..c1c989154337 --- /dev/null +++ b/test/Analysis/rdar-6539791.c @@ -0,0 +1,47 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +typedef const struct __CFAllocator * CFAllocatorRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +typedef signed long CFIndex; +typedef CFIndex CFNumberType; +typedef const void * CFTypeRef; +typedef struct {} CFDictionaryKeyCallBacks, CFDictionaryValueCallBacks; +typedef const struct __CFNumber * CFNumberRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +enum { kCFNumberSInt32Type = 3 }; +CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void *key, const void *value); +void CFRelease(CFTypeRef cf); +CFTypeRef CFRetain(CFTypeRef cf); +extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); +typedef const struct __CFArray * CFArrayRef; +typedef struct __CFArray * CFMutableArrayRef; +void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value); + +void f(CFMutableDictionaryRef y, void* key, void* val_key) { + CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(y, key, x); + CFRelease(x); // the dictionary keeps a reference, so the object isn't deallocated yet + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); + if (value) { + CFDictionaryAddValue(x, val_key, value); // no-warning + CFRelease(value); + CFDictionaryAddValue(y, val_key, value); // no-warning + } +} + +// +// Same issue, except with "AppendValue" functions. +void f2(CFMutableArrayRef x) { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); + // CFArrayAppendValue keeps a reference to value. + CFArrayAppendValue(x, value); + CFRelease(value); + CFRetain(value); + CFRelease(value); // no-warning +} diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m new file mode 100644 index 000000000000..18ab038f6e2e --- /dev/null +++ b/test/Analysis/rdar-6540084.m @@ -0,0 +1,36 @@ +// RUN: clang-cc -analyze -warn-dead-stores -verify %s +// +// This test exercises the live variables analysis (LiveVariables.cpp). +// The case originally identified a non-termination bug. +// +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@interface NSObject {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@class NSArray; +@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; +@interface FooBazController : NSObject {} +@end +typedef struct {} TazVersion; +@class TazNode; +@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end +@interface FooBaz : NSObject {} +@property (nonatomic) BugsBunnyType matchType; +@property (nonatomic, retain) NSArray *papyrus; @end +@implementation FooBazController +- (NSArray *)excitingStuff:(FooBaz *)options { + BugsBunnyType matchType = options.matchType; + NSPredicate *isSearchablePredicate = [NSPredicate predicateWithFormat:@"isSearchable == YES"]; // expected-warning{{receiver 'NSPredicate' is a forward class and corresponding}} // expected-warning{{return type defaults to 'id'}} + for (TazGuttenberg *Guttenberg in options.papyrus) { + NSArray *GuttenbergNodes = [Guttenberg nodes]; // expected-warning{{return type defaults to 'id'}} + NSArray *searchableNodes = [GuttenbergNodes filteredArrayUsingPredicate:isSearchablePredicate]; // expected-warning{{return type defaults to 'id'}} + for (TazNode *node in searchableNodes) { + switch (matchType) { + default: break; + } + } + } +} +@end diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c new file mode 100644 index 000000000000..1e7a2d974bc4 --- /dev/null +++ b/test/Analysis/rdar-6541136-region.c @@ -0,0 +1,19 @@ +// RUN: clang-cc -verify -analyze -checker-cfref -analyzer-store=region %s + +struct tea_cheese { unsigned magic; }; +typedef struct tea_cheese kernel_tea_cheese_t; +extern kernel_tea_cheese_t _wonky_gesticulate_cheese; + +// This test case exercises the ElementRegion::getRValueType() logic. + + +void foo( void ) +{ + kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese; + struct load_wine *cmd = (void*) &wonky[1]; + cmd = cmd; + char *p = (void*) &wonky[1]; + *p = 1; + kernel_tea_cheese_t *q = &wonky[1]; + kernel_tea_cheese_t r = *q; // expected-warning{{out-of-bound memory position}} +} diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c new file mode 100644 index 000000000000..6e6a479136b9 --- /dev/null +++ b/test/Analysis/rdar-6541136.c @@ -0,0 +1,20 @@ +// RUN: clang-cc -verify -analyze -checker-cfref -analyzer-store=basic %s + +struct tea_cheese { unsigned magic; }; +typedef struct tea_cheese kernel_tea_cheese_t; +extern kernel_tea_cheese_t _wonky_gesticulate_cheese; + +// This test case exercises the ElementRegion::getRValueType() logic. +// All it tests is that it does not crash or do anything weird. +// The out-of-bounds-access on line 19 is caught using the region store variant. + +void foo( void ) +{ + kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese; + struct load_wine *cmd = (void*) &wonky[1]; + cmd = cmd; + char *p = (void*) &wonky[1]; + *p = 1; + kernel_tea_cheese_t *q = &wonky[1]; + kernel_tea_cheese_t r = *q; // no-warning +} diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m new file mode 100644 index 000000000000..581d6eacf085 --- /dev/null +++ b/test/Analysis/rdar-6562655.m @@ -0,0 +1,63 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s +// +// This test case mainly checks that the retain/release checker doesn't crash +// on this file. +// +typedef int int32_t; +typedef signed char BOOL; +typedef long NSInteger; +typedef unsigned long NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject {} +@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSResponder : NSObject {} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder { +} +@end enum { +NSNullCellType = 0, NSTextCellType = 1, NSImageCellType = 2 }; +typedef struct __CFlags { + unsigned int botnet:3; +} + _CFlags; +@interface Bar : NSObject { + _CFlags _cFlags; +@private id _support; +} +@end extern NSString *NSControlTintDidChangeNotification; +typedef NSInteger NSBotnet; +@interface NSControl : NSView { +} +@end @class NSAttributedString, NSFont, NSImage, NSSound; +typedef int32_t Baz; +@interface Bar(BarInternal) - (void)_setIsWhite:(BOOL)isWhite; +@end +@interface Bar (BarBotnetCompatibility) +- (NSBotnet)_initialBotnetZorg; +@end +typedef struct _NSRunArrayItem { + unsigned int botnetIsSet:1; +} BarAuxFlags; +@interface BarAuxiliary : NSObject { +@public + NSControl *controlView; + BarAuxFlags auxCFlags; +} +@end +@implementation Bar +static Baz Qux = 0; +- (id)copyWithZone:(NSZone *)zone {} +- (void)encodeWithCoder:(NSCoder *)coder {} +@end +@implementation Bar (BarBotnet) +- (NSBotnet)botnet { + if (!(*(BarAuxiliary **)&self->_support)->auxCFlags.botnetIsSet) { + _cFlags.botnet = [self _initialBotnetZorg]; + } +} +@end diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c new file mode 100644 index 000000000000..9ec38ef7a5f0 --- /dev/null +++ b/test/Analysis/rdar-6582778-basic-store.c @@ -0,0 +1,22 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s + +typedef const void * CFTypeRef; +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +typedef const struct __CFAllocator * CFAllocatorRef; +typedef const struct __CFDate * CFDateRef; + +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); + +void f(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFTypeRef vals[] = { CFDateCreate(0, t) }; // no-warning +} + +CFTypeRef global; + +void g(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + global = CFDateCreate(0, t); // no-warning +} diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m new file mode 100644 index 000000000000..5d1fa37c46a8 --- /dev/null +++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m @@ -0,0 +1,25 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify + +typedef struct Foo { int x; } Bar; + +@interface MyClass {} +- (Bar)foo; +@end +@implementation MyClass +- (Bar)foo { + struct Foo f = { 0 }; + return f; +} +@end + +void createFoo() { + MyClass *obj = 0; + Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}} +} + +void createFoo2() { + MyClass *obj = 0; + [obj foo]; // no-warning + Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}} +} + diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m new file mode 100644 index 000000000000..bea404799ba3 --- /dev/null +++ b/test/Analysis/refcnt_naming.m @@ -0,0 +1,62 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +typedef const struct __CFURL * CFURLRef; +extern CFURLRef CFURLCreateWithString(CFAllocatorRef allocator, CFStringRef URLString, CFURLRef baseURL); +typedef signed char BOOL; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@interface NSObject {} @end +@class NSArray, NSString, NSURL; + +@interface NamingTest : NSObject {} +-(NSObject*)photocopy; // read as "photocopy" +-(NSObject*)photoCopy; // read as "photo Copy" +-(NSObject*)__blebPRCopy; // read as "bleb PRCopy" +-(NSObject*)__blebPRcopy; // read as "bleb P Rcopy" +-(NSObject*)new_theprefixdoesnotcount; // read as "theprefixdoesnotcount" +-(NSObject*)newestAwesomeStuff; // read as "newest awesome stuff" + +@end + +@interface MyClass : NSObject +{ + id myObject; +} +- (NSURL *)myMethod:(NSString *)inString; +- (NSURL *)getMethod:(NSString*)inString; +- (void)addObject:(id)X; +@end + +@implementation MyClass + +- (NSURL *)myMethod:(NSString *)inString +{ + NSURL *url = (NSURL *)CFURLCreateWithString(0, (CFStringRef)inString, 0); // expected-warning{{leak}} + return url; +} + +- (NSURL *)getMethod:(NSString *)inString +{ + NSURL *url = (NSURL *)CFURLCreateWithString(0, (CFStringRef)inString, 0); + [self addObject:url]; + return url; // no-warning +} + +void testNames(NamingTest* x) { + [x photocopy]; // no-warning + [x photoCopy]; // expected-warning{{leak}} + [x __blebPRCopy]; // expected-warning{{leak}} + [x __blebPRcopy]; // no-warning + [x new_theprefixdoesnotcount]; // no-warning + [x newestAwesomeStuff]; // no-warning +} + + +- (void)addObject:(id)X +{ + myObject = X; +} + +@end diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m new file mode 100644 index 000000000000..ed172e431e99 --- /dev/null +++ b/test/Analysis/region-1.m @@ -0,0 +1,90 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// +// This test case simply should not crash. It evaluates the logic of not +// using MemRegion::getRValueType in incorrect places. + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +- (Class)class; +- (BOOL)isLegOfClass:(Class)aClass; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} +@end @class NSArray; +@interface NSResponder : NSObject { +} +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@class JabasectItem; +@protocol EcoClassifier; +@protocol EcoClassInterfaceCommons @end @protocol EcoImplementation; +@protocol EcoBehavioredClassifier - (NSArray *) implementations; +@end enum { +CK_UNRESTRICTED= 0, CK_READ_ONLY, CK_ADD_ONLY, CK_REMOVE_ONLY }; +@protocol EcoClass - (NSArray *) ownedAttributes; +@end @protocol EcoNamespace; +@protocol EcoType; +@protocol EcoClassifier - (NSArray *) features; +@end @protocol EcoComment; +@protocol EcoElement - (NSArray *) ownedElements; +@end @protocol EcoDirectedRelationship; +@protocol EcoNamedElement - (NSString *) name; +@end extern NSString *const JabaPathSeparator; +@protocol EcoNamespace - (NSArray *) Legs; +@end enum { +PDK_IN=0, PDK_INOUT, PDK_OUT, PDK_RETURN }; +@interface EcoElementImp : NSObject { +} +@end @class EcoNamespace; +@interface EcoNamedElementImp : EcoElementImp { +} +@end @interface EcoNamespaceImp : EcoNamedElementImp { +} +@end @class JabaSCDocController, JabaSCDisplaySpecification; +@interface JabaSCSharedDiagramViewController : NSObject { +} +@end extern NSString *const JabaSCsectGraphicNamesectIdentifier; +@interface EcoClassifierImp : EcoNamespaceImp { +} +@end @class EcoOperationImp; +@interface EcoClassImp : EcoClassifierImp { +} +@end extern NSString *const JabaAddedUMLElements; +@class JabaSCClass, JabaSCInterface, JabaSCOperation; +@class DosLegVaseSymbol, DosProtocolSymbol, DosMethodSymbol, DosFileReference; +@interface HancodeFett : NSObject { +} ++ (DosLegVaseSymbol *) symbolFromClass: (JabaSCClass *) clz; +@end enum _JabaSourceLanguage { +JabaSourceUnknown=0, JabaSourcePrawn, JabaSourceC, JabaSourceCPP, JabaSourceObjectiveC }; +typedef NSUInteger JabaSourceLanguage; +@protocol JabaSCClassifier - (JabaSourceLanguage)language; +@end @interface JabaSCClass : EcoClassImp { +} +@end @class DosGlobalID, DosPQuLC, DosPQuUnLC; +@protocol XCProxyObjectProtocol - (id) representedObject; +@end typedef union _Dossymbollocation { +} + DosRecordArrPrl; +@interface DosIndexEntry : NSObject { +} +@end @class DosProjectIndex, DosTextPapyruswiggle, DosDocPapyruswiggle, DosLegVaseSymbol; +@interface DosSymbol : DosIndexEntry { +} +@end @interface DosLegVaseSymbol : DosSymbol { +} +@end typedef enum _DosTextRangeType { +Dos_CharacterRangeType = 0, Dos_LineRangeType = 1 } + DosTextRangeType; +@implementation JabaSCSharedDiagramViewController + (NSImage *)findImageNamed:(NSString *)name { +} +- (void)revealSourceInEditor:(JabasectItem *)sectItem duperGesture:(BOOL)duperGesture { + id selectedElement = [sectItem representedObject]; + id selectedClassifier = selectedElement; + DosSymbol *symbol=((void *)0); + if([selectedClassifier isLegOfClass:[JabaSCClass class]]) { + symbol = [HancodeFett symbolFromClass:(JabaSCClass *) selectedClassifier]; + } +} diff --git a/test/Analysis/region-only-test.c b/test/Analysis/region-only-test.c new file mode 100644 index 000000000000..fdc740488a2c --- /dev/null +++ b/test/Analysis/region-only-test.c @@ -0,0 +1,13 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s + +// Region store must be enabled for tests in this file. + +// Exercise creating ElementRegion with symbolic super region. +void foo(int* p) { + int *x; + int a; + if (p[0] == 1) + x = &a; + if (p[0] == 1) + *x; // no-warning +} diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m new file mode 100644 index 000000000000..b16c231ce23b --- /dev/null +++ b/test/Analysis/retain-release-basic-store.m @@ -0,0 +1,102 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not including Foundation.h directly makes this test case both svelte and +// portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long UInt32; +typedef signed long CFIndex; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern CFTypeRef CFRetain(CFTypeRef cf); +extern void CFRelease(CFTypeRef cf); +typedef struct { +} +CFArrayCallBacks; +extern const CFArrayCallBacks kCFTypeArrayCallBacks; +typedef const struct __CFArray * CFArrayRef; +typedef struct __CFArray * CFMutableArrayRef; +extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks); +extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); +typedef const struct __CFDictionary * CFDictionaryRef; +typedef UInt32 CFStringEncoding; +enum { +kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 }; +extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate); +typedef __darwin_natural_t natural_t; +typedef natural_t mach_port_name_t; +typedef mach_port_name_t mach_port_t; +typedef signed char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} +@end typedef float CGFloat; +typedef double NSTimeInterval; +@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end enum { +NSObjCNoType = 0, NSObjCVoidType = 'v', NSObjCCharType = 'c', NSObjCShortType = 's', NSObjCLongType = 'l', NSObjCLonglongType = 'q', NSObjCFloatType = 'f', NSObjCDoubleType = 'd', NSObjCBoolType = 'B', NSObjCSelectorType = ':', NSObjCObjectType = '@', NSObjCStructType = '{', NSObjCPointerType = '^', NSObjCStringType = '*', NSObjCArrayType = '[', NSObjCUnionType = '(', NSObjCBitfield = 'b' } +__attribute__((deprecated)); +typedef int kern_return_t; +typedef kern_return_t mach_error_t; +typedef mach_port_t io_object_t; +typedef io_object_t io_service_t; +typedef struct __DASession * DASessionRef; +extern DASessionRef DASessionCreate( CFAllocatorRef allocator ); +typedef struct __DADisk * DADiskRef; +extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name ); +extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media ); +extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk ); +extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk ); +@interface NSAppleEventManager : NSObject { +} +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C }; +typedef mach_error_t DAReturn; +typedef const struct __DADissenter * DADissenterRef; +extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ); + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +// Test to see if we supresss an error when we store the pointer +// to a struct. This is because the value "escapes" the basic reasoning +// of basic store. + +struct foo { + NSDate* f; +}; + +CFAbsoluteTime f4() { + struct foo x; + + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + [((NSDate*) date) retain]; + CFRelease(date); + CFDateGetAbsoluteTime(date); // no-warning + x.f = (NSDate*) date; + [((NSDate*) date) release]; + t = CFDateGetAbsoluteTime(date); // no-warning + return t; +} + diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m new file mode 100644 index 000000000000..70ad54f8aa4a --- /dev/null +++ b/test/Analysis/retain-release-gc-only.m @@ -0,0 +1,161 @@ +// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc-only %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -verify %s + +//===----------------------------------------------------------------------===// +// Header stuff. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef struct {} div_t; +typedef unsigned long UInt32; +typedef signed long CFIndex; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern CFTypeRef CFRetain(CFTypeRef cf); +extern void CFRelease(CFTypeRef cf); +typedef struct { +} +CFArrayCallBacks; +extern const CFArrayCallBacks kCFTypeArrayCallBacks; +typedef const struct __CFArray * CFArrayRef; +typedef struct __CFArray * CFMutableArrayRef; +extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks); +extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); +extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value); +typedef const struct __CFDictionary * CFDictionaryRef; +typedef UInt32 CFStringEncoding; +enum { +kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 }; +extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate); +typedef __darwin_natural_t natural_t; +typedef natural_t mach_port_name_t; +typedef mach_port_name_t mach_port_t; +typedef struct { +} +CFRunLoopObserverContext; +typedef signed char BOOL; +typedef unsigned int 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; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} ++ (id)alloc; ++ (id)allocWithZone:(NSZone *)zone; +@end typedef float CGFloat; +@interface NSString : NSObject - (NSUInteger)length; +- (const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +- (id)init; +- (void)dealloc; +@end extern NSString * const NSCurrentLocaleDidChangeNotification ; +@protocol NSLocking - (void)lock; +@end extern NSString * const NSUndoManagerCheckpointNotification; +typedef enum { +ACL_READ_DATA = (1<<1), ACL_LIST_DIRECTORY = (1<<1), ACL_WRITE_DATA = (1<<2), ACL_ADD_FILE = (1<<2), ACL_EXECUTE = (1<<3), ACL_SEARCH = (1<<3), ACL_DELETE = (1<<4), ACL_APPEND_DATA = (1<<5), ACL_ADD_SUBDIRECTORY = (1<<5), ACL_DELETE_CHILD = (1<<6), ACL_READ_ATTRIBUTES = (1<<7), ACL_WRITE_ATTRIBUTES = (1<<8), ACL_READ_EXTATTRIBUTES = (1<<9), ACL_WRITE_EXTATTRIBUTES = (1<<10), ACL_READ_SECURITY = (1<<11), ACL_WRITE_SECURITY = (1<<12), ACL_CHANGE_OWNER = (1<<13) } +acl_entry_id_t; +typedef int kern_return_t; +typedef kern_return_t mach_error_t; +typedef mach_port_t io_object_t; +typedef io_object_t io_service_t; +typedef struct __DASession * DASessionRef; +extern DASessionRef DASessionCreate( CFAllocatorRef allocator ); +typedef struct __DADisk * DADiskRef; +extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name ); +extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media ); +extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk ); +extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk ); +@interface NSResponder : NSObject { +} +@end @class NSColor, NSFont, NSNotification; +typedef struct __CFlags { +} +_CFlags; +@interface NSCell : NSObject { +} +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +@interface NSManagedObjectContext : NSObject { +} +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C }; +typedef mach_error_t DAReturn; +typedef const struct __DADissenter * DADissenterRef; +extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ); + +CFTypeRef CFMakeCollectable(CFTypeRef cf) ; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +void f1() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning + id x = [(id) A autorelease]; + CFRelease((CFMutableArrayRef) x); +} + +void f2() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}} + id x = [(id) A retain]; + [x release]; + [x release]; +} + +void f3() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}} + CFMakeCollectable(A); + CFRetain(A); +} + +// Test return of non-owned objects in contexts where an owned object +// is expected. +@interface TestReturnNotOwnedWhenExpectedOwned +- (NSString*)newString; +- (CFMutableArrayRef)newArray; +@end + +@implementation TestReturnNotOwnedWhenExpectedOwned +- (NSString*)newString { + NSString *s = [NSString stringWithUTF8String:"hello"]; // expected-warning{{Potential leak (when using garbage collection) of an object allocated on line 136 and stored into 's'}} + CFRetain(s); + return s; +} +- (CFMutableArrayRef)newArray{ + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// Tests of ownership attributes. +//===----------------------------------------------------------------------===// + +@interface TestOwnershipAttr : NSObject +- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained)); +- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained)); +@end + +void test_attr_1(TestOwnershipAttr *X) { + NSString *str = [X returnsAnOwnedString]; // no-warning +} + +void test_attr_1b(TestOwnershipAttr *X) { + NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}} +} + diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m new file mode 100644 index 000000000000..66950e2190ed --- /dev/null +++ b/test/Analysis/retain-release-region-store.m @@ -0,0 +1,118 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not including Foundation.h directly makes this test case both svelte and +// portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long UInt32; +typedef signed long CFIndex; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern CFTypeRef CFRetain(CFTypeRef cf); +extern void CFRelease(CFTypeRef cf); +typedef struct { +} +CFArrayCallBacks; +extern const CFArrayCallBacks kCFTypeArrayCallBacks; +typedef const struct __CFArray * CFArrayRef; +typedef struct __CFArray * CFMutableArrayRef; +extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks); +extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); +typedef const struct __CFDictionary * CFDictionaryRef; +typedef UInt32 CFStringEncoding; +enum { +kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 }; +extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate); +typedef __darwin_natural_t natural_t; +typedef natural_t mach_port_name_t; +typedef mach_port_name_t mach_port_t; +typedef signed char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} +@end typedef float CGFloat; +typedef double NSTimeInterval; +@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end enum { +NSObjCNoType = 0, NSObjCVoidType = 'v', NSObjCCharType = 'c', NSObjCShortType = 's', NSObjCLongType = 'l', NSObjCLonglongType = 'q', NSObjCFloatType = 'f', NSObjCDoubleType = 'd', NSObjCBoolType = 'B', NSObjCSelectorType = ':', NSObjCObjectType = '@', NSObjCStructType = '{', NSObjCPointerType = '^', NSObjCStringType = '*', NSObjCArrayType = '[', NSObjCUnionType = '(', NSObjCBitfield = 'b' } +__attribute__((deprecated)); +typedef int kern_return_t; +typedef kern_return_t mach_error_t; +typedef mach_port_t io_object_t; +typedef io_object_t io_service_t; +typedef struct __DASession * DASessionRef; +extern DASessionRef DASessionCreate( CFAllocatorRef allocator ); +typedef struct __DADisk * DADiskRef; +extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name ); +extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media ); +extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk ); +extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk ); +@interface NSAppleEventManager : NSObject { +} +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C }; +typedef mach_error_t DAReturn; +typedef const struct __DADissenter * DADissenterRef; +extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ); + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +// Test to see if we *issue* an error when we store the pointer +// to a struct. This differs from basic store. + +struct foo { + NSDate* f; +}; + +CFAbsoluteTime f4() { + struct foo x; + + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + [((NSDate*) date) retain]; + CFRelease(date); + CFDateGetAbsoluteTime(date); // no-warning + x.f = (NSDate*) date; + [((NSDate*) date) release]; + t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}} + return t; +} + +// Test that assigning to an self.ivar loses track of an object. +// This is a temporary hack to reduce false positives. +@interface Test3 : NSObject { + id myObj; +} +- (void)test_self_assign_ivar; +@end + +@implementation Test3 +- (void)test_self_assign_ivar { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); // no-warning + myObj = (id) date; +} +@end + + diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m new file mode 100644 index 000000000000..3ff007ed8b3a --- /dev/null +++ b/test/Analysis/retain-release.m @@ -0,0 +1,708 @@ +//>>SLICER +// RUN: clang-cc -analyze -checker-cfref -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +// +// #include +// #include +// #include +// #include +// #include +// +// It includes the basic definitions for the test cases below. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned int UInt32; +typedef signed long CFIndex; +typedef const void * CFTypeRef; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern CFTypeRef CFRetain(CFTypeRef cf); +extern void CFRelease(CFTypeRef cf); +extern const CFAllocatorRef kCFAllocatorDefault; +typedef struct { +} +CFArrayCallBacks; +extern const CFArrayCallBacks kCFTypeArrayCallBacks; +typedef const struct __CFArray * CFArrayRef; +typedef struct __CFArray * CFMutableArrayRef; +extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks); +extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); +extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value); +typedef const struct __CFDictionary * CFDictionaryRef; +typedef UInt32 CFStringEncoding; +enum { +kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 }; +extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); +CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate); +enum { +kCFCalendarComponentsWrap = (1UL << 0) }; +typedef __darwin_natural_t natural_t; +typedef natural_t mach_port_name_t; +typedef mach_port_name_t mach_port_t; +typedef int kern_return_t; +typedef kern_return_t mach_error_t; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +- (id)autorelease; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end @interface NSObject { +} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@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 @interface NSArray : NSObject - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end typedef double NSTimeInterval; +@interface NSDate : NSObject - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end enum { +NSWrapCalendarComponents = kCFCalendarComponentsWrap, }; +@interface NSString : NSObject - (NSUInteger)length; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @interface NSData : NSObject - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end @interface NSDictionary : NSObject - (NSUInteger)count; +@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; +- (void)setObject:(id)anObject forKey:(id)aKey; +@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems; +struct CGRect { +}; +typedef struct CGRect CGRect; +- (id)init; +typedef mach_port_t io_object_t; +typedef io_object_t io_service_t; +typedef struct __DASession * DASessionRef; +extern DASessionRef DASessionCreate( CFAllocatorRef allocator ); +typedef struct __DADisk * DADiskRef; +extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name ); +extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media ); +extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk ); +extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk ); +typedef struct CGColorSpace *CGColorSpaceRef; +typedef struct CGImage *CGImageRef; +@end @class CIContext; +@class NSArray, NSError, NSEvent, NSMenu, NSUndoManager, NSWindow; +@interface NSResponder : NSObject { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder { +} +@end @class NSColor, NSFont, NSNotification; +@protocol NSValidatedUserInterfaceItem - (SEL)action; +@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id )anItem; +@end typedef struct NSThreadPrivate _NSThreadPrivate; +@interface NSApplication : NSResponder { +} +@end enum { +NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 }; +typedef NSUInteger NSApplicationTerminateReply; +@protocol NSApplicationDelegate @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +@end enum { +NSUserInterfaceLayoutDirectionLeftToRight = 0, NSUserInterfaceLayoutDirectionRightToLeft = 1 }; +@interface CIImage : NSObject { +} +typedef int CIFormat; +typedef struct __SFlags { +} +_SFlags; +@end extern NSString * const kCAGravityCenter __attribute__((visibility("default"))); +enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C }; +typedef mach_error_t DAReturn; +typedef const struct __DADissenter * DADissenterRef; +extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ); +@interface CIContext: NSObject { +} +- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r; +- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs; +@end @protocol QCCompositionRenderer @end @interface QCRenderer : NSObject { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end @interface QCView : NSView { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +CFAbsoluteTime f1() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + CFRetain(date); + CFRelease(date); + CFDateGetAbsoluteTime(date); // no-warning + CFRelease(date); + t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}} + return t; +} + +CFAbsoluteTime f2() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + [((NSDate*) date) retain]; + CFRelease(date); + CFDateGetAbsoluteTime(date); // no-warning + [((NSDate*) date) release]; + t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}} + return t; +} + + +NSDate* global_x; + +// Test to see if we supresss an error when we store the pointer +// to a global. + +CFAbsoluteTime f3() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + [((NSDate*) date) retain]; + CFRelease(date); + CFDateGetAbsoluteTime(date); // no-warning + global_x = (NSDate*) date; + [((NSDate*) date) release]; + t = CFDateGetAbsoluteTime(date); // no-warning + return t; +} + +//--------------------------------------------------------------------------- +// Test case 'f4' differs for region store and basic store. See +// retain-release-region-store.m and retain-release-basic-store.m. +//--------------------------------------------------------------------------- + +// Test a leak. + +CFAbsoluteTime f5(int x) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); // expected-warning{{leak}} + + if (x) + CFRelease(date); + + return t; +} + +// Test a leak involving the return. + +CFDateRef f6(int x) { + CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning{{leak}} + CFRetain(date); + return date; +} + +// Test a leak involving an overwrite. + +CFDateRef f7() { + CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}} + CFRetain(date); + date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); + return date; +} + +// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and +// has the word create. +CFDateRef MyDateCreate(); + +CFDateRef f8() { + CFDateRef date = MyDateCreate(); // expected-warning{{leak}} + CFRetain(date); + return date; +} + +CFDateRef f9() { + CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); + int *p = 0; + // When allocations fail, CFDateCreate can return null. + if (!date) *p = 1; // expected-warning{{null}} + return date; +} + +// Handle DiskArbitration API: +// +// http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/DiscArbitrationFramework/ +// +void f10(io_service_t media, DADiskRef d, CFStringRef s) { + DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, 0, "hello"); // expected-warning{{leak}} + if (disk) NSLog(@"ok"); + + disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, 0, media); // expected-warning{{leak}} + if (disk) NSLog(@"ok"); + + CFDictionaryRef dict = DADiskCopyDescription(d); // expected-warning{{leak}} + if (dict) NSLog(@"ok"); + + disk = DADiskCopyWholeDisk(d); // expected-warning{{leak}} + if (disk) NSLog(@"ok"); + + DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault, // expected-warning{{leak}} + kDAReturnSuccess, s); + if (dissenter) NSLog(@"ok"); + + DASessionRef session = DASessionCreate(kCFAllocatorDefault); // expected-warning{{leak}} + if (session) NSLog(@"ok"); +} + +// Test retain/release checker with CFString and CFMutableArray. +void f11() { + // Create the array. + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); + + // Create a string. + CFStringRef s1 = CFStringCreateWithCString(0, "hello world", + kCFStringEncodingUTF8); + + // Add the string to the array. + CFArrayAppendValue(A, s1); + + // Decrement the reference count. + CFRelease(s1); // no-warning + + // Get the string. We don't own it. + s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0); + + // Release the array. + CFRelease(A); // no-warning + + // Release the string. This is a bug. + CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}} +} + +// PR 3337: Handle functions declared using typedefs. +typedef CFTypeRef CREATEFUN(); +CREATEFUN MyCreateFun; + +void f12() { + CFTypeRef o = MyCreateFun(); // expected-warning {{leak}} +} + +void f13_autorelease() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning + [(id) A autorelease]; // no-warning +} + +void f13_autorelease_b() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); + [(id) A autorelease]; + [(id) A autorelease]; // expected-warning{{Object sent -autorelease too many times}} +} + +CFMutableArrayRef f13_autorelease_c() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); + [(id) A autorelease]; + [(id) A autorelease]; + return A; // expected-warning{{Object sent -autorelease too many times}} +} + +CFMutableArrayRef f13_autorelease_d() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); + [(id) A autorelease]; + [(id) A autorelease]; + CFMutableArrayRef B = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Object sent -autorelease too many times}} + CFRelease(B); // no-warning +} + + +// This case exercises the logic where the leak site is the same as the allocation site. +void f14_leakimmediately() { + CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}} +} + +// Test that we track an allocated object beyond the point where the *name* +// of the variable storing the reference is no longer live. +void f15() { + // Create the array. + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); + CFMutableArrayRef *B = &A; + // At this point, the name 'A' is no longer live. + CFRelease(*B); // no-warning +} + + +// Test basic tracking of ivars associated with 'self'. For the retain/release +// checker we currently do not want to flag leaks associated with stores +// of tracked objects to ivars. +@interface SelfIvarTest : NSObject { + id myObj; +} +- (void)test_self_tracking; +@end + +@implementation SelfIvarTest +- (void)test_self_tracking { + myObj = (id) CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} +@end + +// Test return of non-owned objects in contexts where an owned object +// is expected. +@interface TestReturnNotOwnedWhenExpectedOwned +- (NSString*)newString; +@end + +@implementation TestReturnNotOwnedWhenExpectedOwned +- (NSString*)newString { + NSString *s = [NSString stringWithUTF8String:"hello"]; + return s; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}} +} +@end + +// +int isFoo(char c); + +static void rdar_6659160(char *inkind, char *inname) +{ + // We currently expect that [NSObject alloc] cannot fail. This + // will be a toggled flag in the future. It can indeed return null, but + // Cocoa programmers generally aren't expected to reason about out-of-memory + // conditions. + NSString *kind = [[NSString alloc] initWithUTF8String:inkind]; // expected-warning{{leak}} + + // We do allow stringWithUTF8String to fail. This isn't really correct, as + // far as returning 0. In most error conditions it will throw an exception. + // If allocation fails it could return 0, but again this + // isn't expected. + NSString *name = [NSString stringWithUTF8String:inname]; + if(!name) + return; + + const char *kindC = 0; + const char *nameC = 0; + + // In both cases, we cannot reach a point down below where we + // dereference kindC or nameC with either being null. This is because + // we assume that [NSObject alloc] doesn't fail and that we have the guard + // up above. + + if(kind) + kindC = [kind UTF8String]; + if(name) + nameC = [name UTF8String]; + if(!isFoo(kindC[0])) // expected-warning{{null}} + return; + if(!isFoo(nameC[0])) // no-warning + return; + + [kind release]; + [name release]; // expected-warning{{Incorrect decrement of the reference count}} +} + +// PR 3677 - 'allocWithZone' should be treated as following the Cocoa naming +// conventions with respect to 'return'ing ownership. +@interface PR3677: NSObject @end +@implementation PR3677 ++ (id)allocWithZone:(NSZone *)inZone { + return [super allocWithZone:inZone]; // no-warning +} +@end + +// PR 3820 - Reason about calls to -dealloc +void pr3820_DeallocInsteadOfRelease(void) +{ + id foo = [[NSString alloc] init]; // no-warning + [foo dealloc]; + // foo is not leaked, since it has been deallocated. +} + +void pr3820_ReleaseAfterDealloc(void) +{ + id foo = [[NSString alloc] init]; + [foo dealloc]; + [foo release]; // expected-warning{{used after it is release}} + // NSInternalInconsistencyException: message sent to deallocated object +} + +void pr3820_DeallocAfterRelease(void) +{ + NSLog(@"\n\n[%s]", __FUNCTION__); + id foo = [[NSString alloc] init]; + [foo release]; + [foo dealloc]; // expected-warning{{used after it is released}} + // message sent to released object +} + +// From . The problem here is that 'length' binds to +// '($0 - 1)' after '--length', but SimpleConstraintManager doesn't know how to +// reason about '($0 - 1) > constant'. As a temporary hack, we drop the value +// of '($0 - 1)' and conjure a new symbol. +void rdar6704930(unsigned char *s, unsigned int length) { + NSString* name = 0; + if (s != 0) { + if (length > 0) { + while (length > 0) { + if (*s == ':') { + ++s; + --length; + name = [[NSString alloc] init]; // no-warning + break; + } + ++s; + --length; + } + if ((length == 0) && (name != 0)) { + [name release]; + name = 0; + } + if (length == 0) { // no ':' found -> use it all as name + name = [[NSString alloc] init]; // no-warning + } + } + } + + if (name != 0) { + [name release]; + } +} + +//===----------------------------------------------------------------------===// +// +// One build of the analyzer accidentally stopped tracking the allocated +// object after the 'retain'. +//===----------------------------------------------------------------------===// + +@interface rdar_6833332 : NSObject { + NSWindow *window; +} +@property (nonatomic, retain) NSWindow *window; +@end + +@implementation rdar_6833332 +@synthesize window; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}} + + [dict setObject:@"foo" forKey:@"bar"]; + + NSLog(@"%@", dict); +} +- (void)dealloc { + [window release]; + [super dealloc]; +} +@end + +//===----------------------------------------------------------------------===// +// clang checker fails to catch use-after-release +//===----------------------------------------------------------------------===// + +int rdar_6257780_Case1() { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSArray *array = [NSArray array]; + [array release]; // expected-warning{{Incorrect decrement of the reference count of an object is not owned at this point by the caller}} + [pool drain]; + return 0; +} + +//===----------------------------------------------------------------------===// +// Checker should understand new/setObject:/release constructs +//===----------------------------------------------------------------------===// + +void rdar_6866843() { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSMutableDictionary* dictionary = [[NSMutableDictionary alloc] init]; + NSArray* array = [[NSArray alloc] init]; + [dictionary setObject:array forKey:@"key"]; + [array release]; + // Using 'array' here should be fine + NSLog(@"array = %@\n", array); // no-warning + // Now the array is released + [dictionary release]; + [pool drain]; +} + + +//===----------------------------------------------------------------------===// +// Classes typedef-ed to CF objects should get the same treatment as CF objects +//===----------------------------------------------------------------------===// + +typedef CFTypeRef OtherRef; + +@interface RDar6877235 : NSObject {} +- (CFTypeRef)_copyCFTypeRef; +- (OtherRef)_copyOtherRef; +@end + +@implementation RDar6877235 +- (CFTypeRef)_copyCFTypeRef { + return [[NSString alloc] init]; // no-warning +} +- (OtherRef)_copyOtherRef { + return [[NSString alloc] init]; // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// false positive - init method returns an object owned by caller +//===----------------------------------------------------------------------===// + +@interface RDar6320065 : NSObject { + NSString *_foo; +} +- (id)initReturningNewClass; +- (id)initReturningNewClassBad; +- (id)initReturningNewClassBad2; +@end + +@interface RDar6320065Subclass : RDar6320065 +@end + +@implementation RDar6320065 +- (id)initReturningNewClass { + [self release]; + self = [[RDar6320065Subclass alloc] init]; // no-warning + return self; +} +- (id)initReturningNewClassBad { + [self release]; + [[RDar6320065Subclass alloc] init]; // expected-warning {{leak}} + return self; +} +- (id)initReturningNewClassBad2 { + [self release]; + self = [[RDar6320065Subclass alloc] init]; + return [self autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}} +} + +@end + +@implementation RDar6320065Subclass +@end + +int RDar6320065_test() { + RDar6320065 *test = [[RDar6320065 alloc] init]; // no-warning + [test release]; + return 0; +} + +//===----------------------------------------------------------------------===// +// [NSData dataWithBytesNoCopy] does not return a retained object +//===----------------------------------------------------------------------===// + +@interface RDar6859457 : NSObject {} +- (NSString*) NoCopyString; +- (NSString*) noCopyString; +@end + +@implementation RDar6859457 +- (NSString*) NoCopyString { return [[NSString alloc] init]; } // no-warning +- (NSString*) noCopyString { return [[NSString alloc] init]; } // no-warning +@end + +void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) { + [x NoCopyString]; // expected-warning{{leak}} + [x noCopyString]; // expected-warning{{leak}} + [NSData dataWithBytesNoCopy:bytes length:dataLength]; // no-warning + [NSData dataWithBytesNoCopy:bytes length:dataLength freeWhenDone:1]; // no-warning +} + +//===----------------------------------------------------------------------===// +// PR 4230 - an autorelease pool is not necessarily leaked during a premature +// return +//===----------------------------------------------------------------------===// + +static void PR4230(void) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // no-warning + NSString *object = [[[NSString alloc] init] autorelease]; // no-warning + return; +} + +//===----------------------------------------------------------------------===// +// Method name that has a null IdentifierInfo* for its first selector slot. +// This test just makes sure that we handle it. +//===----------------------------------------------------------------------===// + +@interface TestNullIdentifier +@end + +@implementation TestNullIdentifier ++ (id):(int)x, ... { + return [[NSString alloc] init]; // expected-warning{{leak}} +} +@end + +//===----------------------------------------------------------------------===// +// don't flag leaks for return types that cannot be +// determined to be CF types +//===----------------------------------------------------------------------===// + +// We don't know if 'struct s6893565' represents a Core Foundation type, so +// we shouldn't emit an error here. +typedef struct s6893565* TD6893565; + +@interface RDar6893565 {} +-(TD6893565)newThing; +@end + +@implementation RDar6893565 +-(TD6893565)newThing { + return (TD6893565) [[NSString alloc] init]; // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// clang: false positives w/QC and CoreImage methods +//===----------------------------------------------------------------------===// + +void rdar6902710(QCView *view, QCRenderer *renderer, CIContext *context, + NSString *str, CIImage *img, CGRect rect, + CIFormat form, CGColorSpaceRef cs) { + [view createSnapshotImageOfType:str]; // expected-warning{{leak}} + [renderer createSnapshotImageOfType:str]; // expected-warning{{leak}} + [context createCGImage:img fromRect:rect]; // expected-warning{{leak}} + [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// +// Tests of ownership attributes. +//===----------------------------------------------------------------------===// + +typedef NSString* MyStringTy; + +@interface TestOwnershipAttr : NSObject +- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained)); // no-warning +- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained)); // no-warning +- (MyStringTy) returnsAnOwnedTypedString __attribute__((ns_returns_retained)); // no-warning +- (int) returnsAnOwnedInt __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}} +@end + +static int ownership_attribute_doesnt_go_here __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}} + +void test_attr_1(TestOwnershipAttr *X) { + NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}} +} + +void test_attr_1b(TestOwnershipAttr *X) { + NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}} +} +//< + +int* f1() { + int x = 0; + return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned.}} expected-warning{{address of stack memory associated with local variable 'x' returned}} +} + +int* f2(int y) { + return &y; // expected-warning{{Address of stack memory associated with local variable 'y' returned.}} expected-warning{{address of stack memory associated with local variable 'y' returned}} +} + +int* f3(int x, int *y) { + int w = 0; + + if (x) + y = &w; + + return y; // expected-warning{{Address of stack memory associated with local variable 'w' returned.}} +} + +void* compound_literal(int x, int y) { + if (x) + return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}} + + int* array[] = {}; + struct s { int z; double y; int w; }; + + if (y) + return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}} + + + void* p = &((struct s){ 42, 0.4, x ? 42 : 0 }); + return p; // expected-warning{{Address of stack memory}} +} + +void* alloca_test() { + void* p = __builtin_alloca(10); + return p; // expected-warning{{Address of stack memory}} +} + diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m new file mode 100644 index 000000000000..161ab8041de1 --- /dev/null +++ b/test/Analysis/uninit-msg-expr.m @@ -0,0 +1,58 @@ +// RUN: clang-cc -analyze -checker-simple -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from +// Foundation.h (Mac OS X). +// +// It includes the basic definitions for the test cases below. +// Not directly including Foundation.h directly makes this test case +// both svelte and portable to non-Mac platforms. +//===----------------------------------------------------------------------===// + +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} @end +@class NSString, NSData; +@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray; +typedef struct {} NSFastEnumerationState; +@protocol NSFastEnumeration +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end +@class NSData, NSIndexSet, NSString, NSURL; +@interface NSArray : NSObject +- (NSUInteger)count; +@end +@interface NSArray (NSArrayCreation) ++ (id)array; +- (NSUInteger)length; +- (void)addObject:(id)object; +@end +extern NSString * const NSUndoManagerCheckpointNotification; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +unsigned f1() { + NSString *aString; + return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}} +} + +unsigned f2() { + NSString *aString = 0; + return [aString length]; // no-warning +} + +void f3() { + NSMutableArray *aArray = [NSArray array]; + NSString *aString; + [aArray addObject:aString]; // expected-warning {{Pass-by-value argument in message expression is undefined.}} +} diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m new file mode 100644 index 000000000000..49eb26984a0b --- /dev/null +++ b/test/Analysis/uninit-ps-rdar6145427.m @@ -0,0 +1,37 @@ +// RUN: clang-cc -analyze -verify -analyzer-store=basic -checker-cfref %s && +// RUN: clang-cc -analyze -verify -analyzer-store=region -checker-cfref %s + +// Delta-Debugging reduced preamble. +typedef signed char BOOL; +typedef unsigned int 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; @end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} + (id)alloc; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSValue : NSObject - (void)getValue:(void *)value; @end +@class NSString, NSData; +typedef struct _NSPoint {} NSRange; +@interface NSValue (NSValueRangeExtensions) ++ (NSValue *)valueWithRange:(NSRange)range; +- (id)objectAtIndex:(NSUInteger)index; +@end +@interface NSAutoreleasePool : NSObject {} - (void)drain; @end +extern NSString * const NSBundleDidLoadNotification; +typedef struct {} NSDecimal; +@interface NSNetService : NSObject {} - (id)init; @end +extern NSString * const NSUndoManagerCheckpointNotification; + +// Test case: + +int main (int argc, const char * argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is an uninitialized value.}} + NSLog(@"%@", someUnintializedPointer); + [pool drain]; + return 0; +} diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c new file mode 100644 index 000000000000..6f3762ee10bf --- /dev/null +++ b/test/Analysis/uninit-vals-ps-region.c @@ -0,0 +1,17 @@ +// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s + +struct s { + int data; +}; + +struct s global; + +void g(int); + +void f4() { + int a; + if (global.data == 0) + a = 3; + if (global.data == 0) // When the true branch is feasible 'a = 3'. + g(a); // no-warning +} diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c new file mode 100644 index 000000000000..41771265367a --- /dev/null +++ b/test/Analysis/uninit-vals-ps.c @@ -0,0 +1,85 @@ +// RUN: clang-cc -analyze -checker-cfref -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +struct FPRec { + void (*my_func)(int * x); +}; + +int bar(int x); + +int f1_a(struct FPRec* foo) { + int x; + (*foo->my_func)(&x); + return bar(x)+1; // no-warning +} + +int f1_b() { + int x; + return bar(x)+1; // expected-warning{{Pass-by-value argument in function call is undefined.}} +} + +int f2() { + + int x; + + if (x+1) // expected-warning{{Branch}} + return 1; + + return 2; +} + +int f2_b() { + int x; + + return ((x+1)+2+((x))) + 1 ? 1 : 2; // expected-warning{{Branch}} +} + +int f3(void) { + int i; + int *p = &i; + if (*p > 0) // expected-warning{{Branch condition evaluates to an uninitialized value}} + return 0; + else + return 1; +} + +void f4_aux(float* x); +float f4(void) { + float x; + f4_aux(&x); + return x; // no-warning +} + +struct f5_struct { int x; }; +void f5_aux(struct f5_struct* s); +int f5(void) { + struct f5_struct s; + f5_aux(&s); + return s.x; // no-warning +} + +int ret_uninit() { + int i; + int *p = &i; + return *p; // expected-warning{{Uninitialized or undefined value returned to caller.}} +} + +// +typedef unsigned char Boolean; +typedef const struct __CFNumber * CFNumberRef; +typedef signed long CFIndex; +typedef CFIndex CFNumberType; +typedef unsigned long UInt32; +typedef UInt32 CFStringEncoding; +typedef const struct __CFString * CFStringRef; +extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr); +extern CFStringRef CFStringConvertEncodingToIANACharSetName(CFStringEncoding encoding); + +CFStringRef rdar_6451816(CFNumberRef nr) { + CFStringEncoding encoding; + // &encoding is casted to void*. This test case tests whether or not + // we properly invalidate the value of 'encoding'. + CFNumberGetValue(nr, 9, &encoding); + return CFStringConvertEncodingToIANACharSetName(encoding); // no-warning +} + diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c new file mode 100644 index 000000000000..d69250b65c0b --- /dev/null +++ b/test/Analysis/uninit-vals.c @@ -0,0 +1,53 @@ +// RUN: clang-cc -analyze -warn-uninit-values -verify %s + +int f1() { + int x; + return x; // expected-warning {{use of uninitialized variable}} +} + +int f2(int x) { + int y; + int z = x + y; // expected-warning {{use of uninitialized variable}} + return z; +} + + +int f3(int x) { + int y; + return x ? 1 : y; // expected-warning {{use of uninitialized variable}} +} + +int f4(int x) { + int y; + if (x) y = 1; + return y; // expected-warning {{use of uninitialized variable}} +} + +int f5() { + int a; + a = 30; // no-warning +} + +void f6(int i) { + int x; + for (i = 0 ; i < 10; i++) + printf("%d",x++); // expected-warning {{use of uninitialized variable}} \ + // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \ + // expected-note{{please include the header or explicitly provide a declaration for 'printf'}} +} + +void f7(int i) { + int x = i; + int y; + for (i = 0; i < 10; i++ ) { + printf("%d",x++); // no-warning + x += y; // expected-warning {{use of uninitialized variable}} + } +} + +int f8(int j) { + int x = 1, y = x + 1; + if (y) // no-warning + return x; + return y; +} diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m new file mode 100644 index 000000000000..7be247e7ca9e --- /dev/null +++ b/test/Analysis/uninit-vals.m @@ -0,0 +1,25 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s && +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s + +typedef unsigned int NSUInteger; + +@interface A +- (NSUInteger)foo; +@end + +NSUInteger f8(A* x){ + const NSUInteger n = [x foo]; + int* bogus; + + if (n > 0) { // tests const cast transfer function logic + NSUInteger i; + + for (i = 0; i < n; ++i) + bogus = 0; + + if (bogus) // no-warning + return n+1; + } + + return n; +} diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m new file mode 100644 index 000000000000..632b395c3e08 --- /dev/null +++ b/test/Analysis/unused-ivars.m @@ -0,0 +1,10 @@ +// RUN: clang-cc -analyze -warn-objc-unused-ivars %s -verify + +@interface A +{ + @private int x; // expected-warning {{Instance variable 'x' in class 'A' is never used}} +} +@end + +@implementation A @end + diff --git a/test/Analysis/xfail-no-outofbounds.c b/test/Analysis/xfail-no-outofbounds.c new file mode 100644 index 000000000000..f2ee732c2570 --- /dev/null +++ b/test/Analysis/xfail-no-outofbounds.c @@ -0,0 +1,7 @@ +// RUN: clang-cc -checker-cfref -analyze -analyzer-store=region -verify %s + +void f() { + long x = 0; + char *y = (char*) &x; + char c = y[0] + y[1] + y[2]; // no-warning +} diff --git a/test/Analysis/xfail_regionstore_wine_crash.c b/test/Analysis/xfail_regionstore_wine_crash.c new file mode 100644 index 000000000000..2628d0dacf6a --- /dev/null +++ b/test/Analysis/xfail_regionstore_wine_crash.c @@ -0,0 +1,12 @@ +// RUN: clang-cc -checker-cfref -analyze -analyzer-store=region -verify %s +// XFAIL + +// When this test passes we should put it in the misc-ps.m test file. +// This test fails now because RegionStoreManager::Retrieve() does correctly +// retrieve the first byte of 'x' when retrieving '*y'. +void foo() { + long x = 0; + char *y = (char *) &x; + if (!*y) + return; +} -- cgit v1.2.3