diff options
author | Zancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au> | 2012-09-24 09:58:17 +1000 |
---|---|---|
committer | Zancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au> | 2012-09-24 09:58:17 +1000 |
commit | 222e2a7620e6520ffaf4fc4e69d79c18da31542e (patch) | |
tree | 7bfbc05bfa3b41c8f9d2e56d53a0bc3e310df239 /clang/test/Analysis | |
parent | 3d206f03985b50beacae843d880bccdc91a9f424 (diff) |
Add the clang library to the repo (with some of my changes, too).
Diffstat (limited to 'clang/test/Analysis')
181 files changed, 28353 insertions, 0 deletions
diff --git a/clang/test/Analysis/CFContainers.mm b/clang/test/Analysis/CFContainers.mm new file mode 100644 index 0000000..7d6c175 --- /dev/null +++ b/clang/test/Analysis/CFContainers.mm @@ -0,0 +1,204 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues,osx.coreFoundation.containers.OutOfBounds -analyzer-store=region -triple x86_64-apple-darwin -verify %s + +typedef const struct __CFAllocator * CFAllocatorRef; +typedef const struct __CFString * CFStringRef; +typedef unsigned char Boolean; +typedef signed long CFIndex; +extern +const CFAllocatorRef kCFAllocatorDefault; +typedef const void * (*CFArrayRetainCallBack)(CFAllocatorRef allocator, const void *value); +typedef void (*CFArrayReleaseCallBack)(CFAllocatorRef allocator, const void *value); +typedef CFStringRef (*CFArrayCopyDescriptionCallBack)(const void *value); +typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); +typedef struct { + CFIndex version; + CFArrayRetainCallBack retain; + CFArrayReleaseCallBack release; + CFArrayCopyDescriptionCallBack copyDescription; + CFArrayEqualCallBack equal; +} CFArrayCallBacks; +typedef const struct __CFArray * CFArrayRef; +CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks); +typedef const struct __CFString * CFStringRef; +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; +typedef CFIndex CFComparisonResult; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef const void * (*CFDictionaryRetainCallBack)(CFAllocatorRef allocator, const void *value); +typedef void (*CFDictionaryReleaseCallBack)(CFAllocatorRef allocator, const void *value); +typedef CFStringRef (*CFDictionaryCopyDescriptionCallBack)(const void *value); +typedef Boolean (*CFDictionaryEqualCallBack)(const void *value1, const void *value2); +typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); +typedef Boolean (*CFSetEqualCallBack)(const void *value1, const void *value2); +typedef const void * (*CFSetRetainCallBack)(CFAllocatorRef allocator, const void *value); +typedef void (*CFSetReleaseCallBack)(CFAllocatorRef allocator, const void *value); +typedef CFStringRef (*CFSetCopyDescriptionCallBack)(const void *value); +typedef struct { + CFIndex version; + CFSetRetainCallBack retain; + CFSetReleaseCallBack release; + CFSetCopyDescriptionCallBack copyDescription; + CFSetEqualCallBack equal; +} CFSetCallBacks; +typedef struct { + CFIndex version; + CFDictionaryRetainCallBack retain; + CFDictionaryReleaseCallBack release; + CFDictionaryCopyDescriptionCallBack copyDescription; + CFDictionaryEqualCallBack equal; +} CFDictionaryKeyCallBacks; +typedef struct { + CFIndex version; + CFDictionaryRetainCallBack retain; + CFDictionaryReleaseCallBack release; + CFDictionaryCopyDescriptionCallBack copyDescription; + CFDictionaryEqualCallBack equal; +} CFDictionaryValueCallBacks; +CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +extern +const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFSet * CFSetRef; +extern +const CFSetCallBacks kCFTypeSetCallBacks; +extern +const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks; +extern +const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); +extern +CFIndex CFArrayGetCount(CFArrayRef theArray); +CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const +CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); +extern +CFSetRef CFSetCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFSetCallBacks *callBacks); +#define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr "")) +#define NULL __null + +// Done with the headers. +// Test experimental.osx.cocoa.ContainerAPI checker. +void testContainers(int **xNoWarn, CFIndex count) { + int x[] = { 1, 2, 3 }; + CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);// expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} + + CFArrayRef fooNoWarn = CFArrayCreate(kCFAllocatorDefault, (const void **) xNoWarn, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0); // no warning + CFArrayRef fooNoWarn2 = CFArrayCreate(kCFAllocatorDefault, 0, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in 0 + CFArrayRef fooNoWarn3 = CFArrayCreate(kCFAllocatorDefault, NULL, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in NULL + + CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks); // expected-warning {{The first argument to 'CFSetCreate' must be a C array of pointer-sized values}} + CFArrayRef* pairs = new CFArrayRef[count]; + CFSetRef fSet = CFSetCreate(kCFAllocatorDefault, (const void**) pairs, count - 1, &kCFTypeSetCallBacks);// no warning +} + +void CreateDict(int *elems) { + const short days28 = 28; + const short days30 = 30; + const short days31 = 31; + CFIndex numValues = 6; + CFStringRef keys[6]; + CFNumberRef values[6]; + keys[0] = CFSTR("January"); values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); + keys[1] = CFSTR("February"); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days28); + keys[2] = CFSTR("March"); values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); + keys[3] = CFSTR("April"); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30); + keys[4] = CFSTR("May"); values[4] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); + keys[5] = CFSTR("June"); values[5] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30); + + const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks; + const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks; + CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning + CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The first argument to 'CFDictionaryCreate' must be a C array of}} + CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}} +} + +void OutOfBoundsSymbolicOffByOne(const void ** input, CFIndex S) { + CFArrayRef array; + array = CFArrayCreate(kCFAllocatorDefault, input, S, 0); + const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning + const void *s2 = CFArrayGetValueAtIndex(array, S-1); // no warning + const void *s3 = CFArrayGetValueAtIndex(array, S); // expected-warning {{Index is out of bounds}} +} + +void OutOfBoundsConst(const void ** input, CFIndex S) { + CFArrayRef array; + array = CFArrayCreate(kCFAllocatorDefault, input, 3, 0); + const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning + const void *s2 = CFArrayGetValueAtIndex(array, 2); // no warning + const void *s3 = CFArrayGetValueAtIndex(array, 5); // expected-warning {{Index is out of bounds}} + + // TODO: The solver is probably not strong enough here. + CFIndex sIndex; + for (sIndex = 0 ; sIndex <= 5 ; sIndex += 3 ) { + const void *s = CFArrayGetValueAtIndex(array, sIndex); + } +} + +void OutOfBoundsZiro(const void ** input, CFIndex S) { + CFArrayRef array; + // The API allows to set the size to 0. Check that we don't undeflow when the size is 0. + array = CFArrayCreate(kCFAllocatorDefault, 0, 0, 0); + const void *s1 = CFArrayGetValueAtIndex(array, 0); // expected-warning {{Index is out of bounds}} +} + +void TestGetCount(CFArrayRef A, CFIndex sIndex) { + CFIndex sCount = CFArrayGetCount(A); + if (sCount > sIndex) + const void *s1 = CFArrayGetValueAtIndex(A, sIndex); + const void *s2 = CFArrayGetValueAtIndex(A, sCount);// expected-warning {{Index is out of bounds}} +} + +typedef void* XX[3]; +void TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count, void* fn[], char cp[]) { + void* x[] = { p1, p2, p3 }; + CFArrayCreate(0, (const void **) &x, count, 0); // no warning + + void* y[] = { p1, p2, p3 }; + CFArrayCreate(0, (const void **) y, count, 0); // no warning + XX *z = &x; + CFArrayCreate(0, (const void **) z, count, 0); // no warning + + CFArrayCreate(0, (const void **) &fn, count, 0); // false negative + CFArrayCreate(0, (const void **) fn, count, 0); // no warning + CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} + + char cc[] = { 0, 2, 3 }; + CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} + CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} +} + +void TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) { + unsigned undefVal; + const void *s1 = CFArrayGetValueAtIndex(A, undefVal); + + unsigned undefVal2; + CFArrayRef B = CFArrayCreate(0, (const void **) &x, undefVal2, 0); + const void *s2 = CFArrayGetValueAtIndex(B, 2); +} + +void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) { + CFArrayRef B = CFArrayCreate(0, (const void **) &x, 4, 0); + const void *s1 = CFArrayGetValueAtIndex(B, 2); + +} + +void TestNullArray() { + CFArrayGetValueAtIndex(0, 0); +} diff --git a/clang/test/Analysis/CFDateGC.m b/clang/test/Analysis/CFDateGC.m new file mode 100644 index 0000000..4884bb9 --- /dev/null +++ b/clang/test/Analysis/CFDateGC.m @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration + +//===----------------------------------------------------------------------===// +// 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) { return 0; } +@protocol NSObject - (BOOL)isEqual:(id)object; +- (oneway void)release; +- (id)retain; +@end +@class NSArray; + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +CFAbsoluteTime CFAbsoluteTimeGetCurrent(); + +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/clang/test/Analysis/CFNumber.c b/clang/test/Analysis/CFNumber.c new file mode 100644 index 0000000..fbbe4d1 --- /dev/null +++ b/clang/test/Analysis/CFNumber.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -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.}} +} + +__attribute__((cf_returns_retained)) 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.}} +} + +// test that the attribute overrides the naming convention. +__attribute__((cf_returns_not_retained)) CFNumberRef CreateNum(unsigned char x) { + return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{leak}} +} + +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/clang/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/clang/test/Analysis/CFRetainRelease_NSAssertionHandler.m new file mode 100644 index 0000000..e0c9be1 --- /dev/null +++ b/clang/test/Analysis/CFRetainRelease_NSAssertionHandler.m @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=basic -analyzer-store=region +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -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 <NSObject> {} - (id)init; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (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,...; +- (void)handleFailureInFunction:(NSString *)functionName 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 + +void pointerFunction (int *x) { + // Manual expansion of NSCAssert( x != 0, @"") + do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] file:[NSString stringWithUTF8String:__FILE__] lineNumber:__LINE__ description:((@""))]; } } while(0); + + *x = 1; // no-warning +} diff --git a/clang/test/Analysis/CGColorSpace.c b/clang/test/Analysis/CGColorSpace.c new file mode 100644 index 0000000..1bd20fa --- /dev/null +++ b/clang/test/Analysis/CGColorSpace.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -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/clang/test/Analysis/CheckNSError.m b/clang/test/Analysis/CheckNSError.m new file mode 100644 index 0000000..d35b686 --- /dev/null +++ b/clang/test/Analysis/CheckNSError.m @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %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 <NSObject> {} @end +@class NSDictionary; +@interface NSError : NSObject <NSCopying, NSCoding> {} ++ (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 occurred}} + *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 occurred}} + *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/clang/test/Analysis/MissingDealloc.m b/clang/test/Analysis/MissingDealloc.m new file mode 100644 index 0000000..51a5912 --- /dev/null +++ b/clang/test/Analysis/MissingDealloc.m @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.cocoa.Dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify +typedef signed char BOOL; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (Class)class; +@end + +@interface NSObject <NSObject> {} +- (void)dealloc; +- (id)init; +@end + +typedef struct objc_selector *SEL; + +// <rdar://problem/6380411>: '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 +- (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 + +//===------------------------------------------------------------------------=== +// <rdar://problem/6380411> +// 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/clang/test/Analysis/NSPanel.m b/clang/test/Analysis/NSPanel.m new file mode 100644 index 0000000..578658e --- /dev/null +++ b/clang/test/Analysis/NSPanel.m @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %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 <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) { NSRect r; return r; } +typedef struct {} NSFastEnumerationState; +@protocol NSFastEnumeration +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end +@class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (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 <NSCoding> {} @end +@protocol NSAnimatablePropertyContainer +- (id)animator; +@end +@protocol NSValidatedUserInterfaceItem +- (SEL)action; +@end +@protocol NSUserInterfaceValidations +- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)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 <NSAnimatablePropertyContainer, NSUserInterfaceValidations> {} +- (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/clang/test/Analysis/NSString.m b/clang/test/Analysis/NSString.m new file mode 100644 index 0000000..4035cc9 --- /dev/null +++ b/clang/test/Analysis/NSString.m @@ -0,0 +1,408 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %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. +//===----------------------------------------------------------------------===// + +#ifdef TEST_64 +typedef long long int64_t; +_Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ); +#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap64Barrier +typedef int64_t intptr_t; +#else +typedef int int32_t; +_Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue ); +#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap32Barrier +typedef int32_t intptr_t; +#endif + +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 <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 <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (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 <NSCopying, NSMutableCopying, NSCoding> - (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 <rdar://problem/6452745>. +// 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]; + } + return 0; +} + +// 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}} +} + +@interface MyString : NSString +@end + +void f14(MyString *s) { + [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil}} +} + +// 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 ); +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 testOSCompareAndSwapXXBarrier_local() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) + [s release]; + else + [old release]; +} + +void testOSCompareAndSwapXXBarrier_local_no_direct_release() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) + return; + else + [old release]; +} + +int testOSCompareAndSwapXXBarrier_id(Class myclass, id xclass) { + if (COMPARE_SWAP_BARRIER(0, (intptr_t) myclass, (intptr_t*) &xclass)) + return 1; + return 0; +} + +void test_objc_atomicCompareAndSwap_local() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!objc_atomicCompareAndSwapPtr(0, s, &old)) + [s release]; + else + [old release]; +} + +void test_objc_atomicCompareAndSwap_local_no_direct_release() { + NSString *old = 0; + NSString *s = [[NSString alloc] init]; // no-warning + if (!objc_atomicCompareAndSwapPtr(0, s, &old)) + return; + else + [old release]; +} + +void test_objc_atomicCompareAndSwap_parameter(NSString **old) { + NSString *s = [[NSString alloc] init]; // no-warning + if (!objc_atomicCompareAndSwapPtr(0, s, old)) + [s release]; + else + [*old release]; +} + +void test_objc_atomicCompareAndSwap_parameter_no_direct_release(NSString **old) { + NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + if (!objc_atomicCompareAndSwapPtr(0, s, old)) + return; + else + [*old release]; +} + + +// Test stringWithFormat (<rdar://problem/6815234>) +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}} + } +} +@end + +void testOSCompareAndSwapXXBarrier_parameter(NSString **old) { + NSString *s = [[NSString alloc] init]; // no-warning + if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) + [s release]; + else + [*old release]; +} + +void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) { + NSString *s = [[NSString alloc] init]; // no-warning + if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) + [s release]; + else + return; +} diff --git a/clang/test/Analysis/NSWindow.m b/clang/test/Analysis/NSWindow.m new file mode 100644 index 0000000..495f8e1 --- /dev/null +++ b/clang/test/Analysis/NSWindow.m @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -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 <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 <NSCoding> {} +@end +@protocol NSAnimatablePropertyContainer +- (id)animator; +@end +extern NSString *NSAnimationTriggerOrderIn ; +@class CIFilter, CALayer, NSDictionary, NSScreen, NSShadow, NSTrackingArea; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> {} @end +@protocol NSValidatedUserInterfaceItem - (SEL)action; @end +@protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)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 <NSAnimatablePropertyContainer, NSUserInterfaceValidations> { + 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/clang/test/Analysis/NoReturn.m b/clang/test/Analysis/NoReturn.m new file mode 100644 index 0000000..ea2efd0 --- /dev/null +++ b/clang/test/Analysis/NoReturn.m @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s + +#include <stdarg.h> + +//===----------------------------------------------------------------------===// +// 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 <NSObject> {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; ++ (id)stringWithFormat:(NSString *)format, ...; +@end +@interface NSSimpleCString : NSString {} @end +@interface NSConstantString : NSSimpleCString @end +extern void *_NSConstantStringClassReference; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; @end +@class NSString, NSDictionary, NSArray; +@interface NSException : NSObject <NSCopying, NSCoding> {} ++ (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/clang/test/Analysis/OSAtomic_mac.cpp b/clang/test/Analysis/OSAtomic_mac.cpp new file mode 100644 index 0000000..8ad7b3c --- /dev/null +++ b/clang/test/Analysis/OSAtomic_mac.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,osx -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s + +// Test handling of OSAtomicCompareAndSwap when C++ inserts "no-op" casts and we +// do a forced load and binding to the environment on an expression that would regularly +// not have an environment binding. This previously triggered a crash (<rdar://problem/9339920>). +// NOTE: It is critical that the function called is OSAtomicCompareAndSwapIntBarrier. +bool OSAtomicCompareAndSwapIntBarrier( int __oldValue, int __newValue, volatile int *__theValue ) ; +static int _rdar9339920_x = 0; +int rdar9339920_aux(); + +int rdar9339920_test() { + int rdar9339920_x = rdar9339920_aux(); + if (rdar9339920_x != _rdar9339920_x) { + if (OSAtomicCompareAndSwapIntBarrier(_rdar9339920_x, rdar9339920_x, &_rdar9339920_x)) + return 1; + } + return 0; +} + diff --git a/clang/test/Analysis/ObjCProperties.m b/clang/test/Analysis/ObjCProperties.m new file mode 100644 index 0000000..b9ed9b9 --- /dev/null +++ b/clang/test/Analysis/ObjCProperties.m @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -Wno-objc-root-class %s -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -Wno-objc-root-class %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/clang/test/Analysis/ObjCRetSigs.m b/clang/test/Analysis/ObjCRetSigs.m new file mode 100644 index 0000000..13078a3 --- /dev/null +++ b/clang/test/Analysis/ObjCRetSigs.m @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s + +int printf(const char *, ...); + +@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/clang/test/Analysis/PR2599.m b/clang/test/Analysis/PR2599.m new file mode 100644 index 0000000..5436063 --- /dev/null +++ b/clang/test/Analysis/PR2599.m @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=range -analyzer-store=region -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 <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 <NSCopying, NSMutableCopying, NSCoding> +- (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"; + +void NSLog(NSString *, ...); + +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/clang/test/Analysis/PR2978.m b/clang/test/Analysis/PR2978.m new file mode 100644 index 0000000..ea139d2 --- /dev/null +++ b/clang/test/Analysis/PR2978.m @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=experimental.osx.cocoa.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]; + return 0; +} + +@end + diff --git a/clang/test/Analysis/PR3991.m b/clang/test/Analysis/PR3991.m new file mode 100644 index 0000000..38d0bc0 --- /dev/null +++ b/clang/test/Analysis/PR3991.m @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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 <NSObject> { +} +@end extern id <NSObject> NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone); +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding> - (unsigned)count; +@end @class NSTimer, NSPort, NSArray; +@class NSURLHandle, NSMutableArray, NSMutableData, NSData, NSURL; +@interface NSResponder : NSObject <NSCoding> { +} +@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; // expected-note {{method definition for 'entries' not found}} +@end extern Class const kGDataUseRegisteredClass ; +@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList; // expected-note {{method definition for 'feedDocList' not found}} +- (NSArray *)directoryPathComponents; // expected-note {{method definition for 'directoryPathComponents' not found}} +- (unsigned int)currentPathComponentIndex; // expected-note {{method definition for 'currentPathComponentIndex' not found}} +- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex; // expected-note {{method definition for 'setCurrentPathComponentIndex:' not found}} +- (NSURL *)folderFeedURL; // expected-note {{method definition for 'folderFeedURL' not found}} +@end + +@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { // expected-warning {{incomplete implementation}} + return 0; +} + +//===----------------------------------------------------------------------===// +// 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]) { + } + } + } + } +} +@end diff --git a/clang/test/Analysis/PR7218.c b/clang/test/Analysis/PR7218.c new file mode 100644 index 0000000..1775e05 --- /dev/null +++ b/clang/test/Analysis/PR7218.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s +char PR7218(char a) { + char buf[2]; + buf[0] = a; + return buf[1]; // expected-warning {{Undefined or garbage value returned to caller}} +} diff --git a/clang/test/Analysis/PR9741.cpp b/clang/test/Analysis/PR9741.cpp new file mode 100644 index 0000000..7497d56 --- /dev/null +++ b/clang/test/Analysis/PR9741.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -cc1 -std=c++11 -Wuninitialized -verify %s + +void f() { + int a[] = { 1, 2, 3 }; + unsigned int u = 0; + for (auto x : a) + ; +} diff --git a/clang/test/Analysis/additive-folding-range-constraints.c b/clang/test/Analysis/additive-folding-range-constraints.c new file mode 100644 index 0000000..32e0cfe --- /dev/null +++ b/clang/test/Analysis/additive-folding-range-constraints.c @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify -analyzer-constraints=range %s + +// These are used to trigger warnings. +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +#define NULL ((void*)0) +#define UINT_MAX (__INT_MAX__ *2U +1U) + +// Each of these adjusted ranges has an adjustment small enough to split the +// solution range across an overflow boundary (Min for <, Max for >). +// This corresponds to one set of branches in RangeConstraintManager. +void smallAdjustmentGT (unsigned a) { + char* b = NULL; + if (a+2 > 1) + b = malloc(1); + if (a == UINT_MAX-1 || a == UINT_MAX) + return; // no-warning + else if (a < UINT_MAX-1) + free(b); + return; // no-warning +} + +void smallAdjustmentGE (unsigned a) { + char* b = NULL; + if (a+2 >= 1) + b = malloc(1); + if (a == UINT_MAX-1) + return; // no-warning + else if (a < UINT_MAX-1 || a == UINT_MAX) + free(b); + return; // no-warning +} + +void smallAdjustmentLT (unsigned a) { + char* b = NULL; + if (a+1 < 2) + b = malloc(1); + if (a == 0 || a == UINT_MAX) + free(b); + return; // no-warning +} + +void smallAdjustmentLE (unsigned a) { + char* b = NULL; + if (a+1 <= 2) + b = malloc(1); + if (a == 0 || a == 1 || a == UINT_MAX) + free(b); + return; // no-warning +} + + +// Each of these adjusted ranges has an adjustment large enough to push the +// comparison value over an overflow boundary (Min for <, Max for >). +// This corresponds to one set of branches in RangeConstraintManager. +void largeAdjustmentGT (unsigned a) { + char* b = NULL; + if (a-2 > UINT_MAX-1) + b = malloc(1); + if (a == 1 || a == 0) + free(b); + else if (a > 1) + free(b); + return; // no-warning +} + +void largeAdjustmentGE (unsigned a) { + char* b = NULL; + if (a-2 >= UINT_MAX-1) + b = malloc(1); + if (a > 1) + return; // no-warning + else if (a == 1 || a == 0) + free(b); + return; // no-warning +} + +void largeAdjustmentLT (unsigned a) { + char* b = NULL; + if (a+2 < 1) + b = malloc(1); + if (a == UINT_MAX-1 || a == UINT_MAX) + free(b); + else if (a < UINT_MAX-1) + return; // no-warning + return; // no-warning +} + +void largeAdjustmentLE (unsigned a) { + char* b = NULL; + if (a+2 <= 1) + b = malloc(1); + if (a < UINT_MAX-1) + return; // no-warning + else if (a == UINT_MAX-1 || a == UINT_MAX) + free(b); + return; // no-warning +} diff --git a/clang/test/Analysis/additive-folding.c b/clang/test/Analysis/additive-folding.c new file mode 100644 index 0000000..beb08aa --- /dev/null +++ b/clang/test/Analysis/additive-folding.c @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,unix.Malloc -verify -analyzer-constraints=basic %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,unix.Malloc -verify -analyzer-constraints=range %s + +// These are used to trigger warnings. +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +#define NULL ((void*)0) +#define UINT_MAX -1U + +//--------------- +// Plus/minus +//--------------- + +void separateExpressions (int a) { + int b = a + 1; + --b; + + char* buf = malloc(1); + if (a != 0 && b == 0) + return; // expected-warning{{never executed}} + free(buf); +} + +void oneLongExpression (int a) { + // Expression canonicalization should still allow this to work, even though + // the first term is on the left. + int b = 15 + a + 15 - 10 - 20; + + char* buf = malloc(1); + if (a != 0 && b == 0) + return; // expected-warning{{never executed}} + free(buf); +} + +void mixedTypes (int a) { + char* buf = malloc(1); + + // Different additive types should not cause crashes when constant-folding. + // This is part of PR7406. + int b = a + 1LL; + if (a != 0 && (b-1) == 0) // not crash + return; // expected-warning{{never executed}} + + int c = a + 1U; + if (a != 0 && (c-1) == 0) // not crash + return; // expected-warning{{never executed}} + + free(buf); +} + +//--------------- +// Comparisons +//--------------- + +// Equality and inequality only +void eq_ne (unsigned a) { + char* b = NULL; + if (a == UINT_MAX) + b = malloc(1); + if (a+1 != 0) + return; // no-warning + if (a-1 != UINT_MAX-1) + return; // no-warning + free(b); +} + +void ne_eq (unsigned a) { + char* b = NULL; + if (a != UINT_MAX) + b = malloc(1); + if (a+1 == 0) + return; // no-warning + if (a-1 == UINT_MAX-1) + return; // no-warning + free(b); +} + +// Mixed typed inequalities (part of PR7406) +// These should not crash. +void mixed_eq_ne (int a) { + char* b = NULL; + if (a == 1) + b = malloc(1); + if (a+1U != 2) + return; // no-warning + if (a-1U != 0) + return; // expected-warning{{never executed}} + free(b); +} + +void mixed_ne_eq (int a) { + char* b = NULL; + if (a != 1) + b = malloc(1); + if (a+1U == 2) + return; // no-warning + if (a-1U == 0) + return; // expected-warning{{never executed}} + free(b); +} + + +// Simple order comparisons with no adjustment +void baselineGT (unsigned a) { + char* b = NULL; + if (a > 0) + b = malloc(1); + if (a == 0) + return; // no-warning + free(b); +} + +void baselineGE (unsigned a) { + char* b = NULL; + if (a >= UINT_MAX) + b = malloc(1); + if (a == UINT_MAX) + free(b); + return; // no-warning +} + +void baselineLT (unsigned a) { + char* b = NULL; + if (a < UINT_MAX) + b = malloc(1); + if (a == UINT_MAX) + return; // no-warning + free(b); +} + +void baselineLE (unsigned a) { + char* b = NULL; + if (a <= 0) + b = malloc(1); + if (a == 0) + free(b); + return; // no-warning +} + + +// Adjustment gives each of these an extra solution! +void adjustedGT (unsigned a) { + char* b = NULL; + if (a-1 > UINT_MAX-1) + b = malloc(1); + return; // expected-warning{{leak}} +} + +void adjustedGE (unsigned a) { + char* b = NULL; + if (a-1 >= UINT_MAX-1) + b = malloc(1); + if (a == UINT_MAX) + free(b); + return; // expected-warning{{leak}} +} + +void adjustedLT (unsigned a) { + char* b = NULL; + if (a+1 < 1) + b = malloc(1); + return; // expected-warning{{leak}} +} + +void adjustedLE (unsigned a) { + char* b = NULL; + if (a+1 <= 1) + b = malloc(1); + if (a == 0) + free(b); + return; // expected-warning{{leak}} +} + + +// Tautologies +void tautologyGT (unsigned a) { + char* b = malloc(1); + if (a > UINT_MAX) + return; // no-warning + free(b); +} + +void tautologyGE (unsigned a) { + char* b = malloc(1); + if (a >= 0) // expected-warning{{always true}} + free(b); + return; // no-warning +} + +void tautologyLT (unsigned a) { + char* b = malloc(1); + if (a < 0) // expected-warning{{always false}} + return; // expected-warning{{never executed}} + free(b); +} + +void tautologyLE (unsigned a) { + char* b = malloc(1); + if (a <= UINT_MAX) + free(b); + return; // no-warning +} diff --git a/clang/test/Analysis/analyzeOneFunction.m b/clang/test/Analysis/analyzeOneFunction.m new file mode 100644 index 0000000..1ff2fc8 --- /dev/null +++ b/clang/test/Analysis/analyzeOneFunction.m @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -analyze -analyze-function="myMethodWithY:withX:" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -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 +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@interface NSObject <NSObject> {} ++(id)alloc; +-(id)init; +-(id)autorelease; +-(id)copy; +-(id)retain; +@end +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; +-(id)initWithFormat:(NSString *)f,...; +-(BOOL)isEqualToString:(NSString *)s; ++ (id)string; +@end + +@interface Test1 : NSObject { + NSString *text; +} +-(id)myMethod; +-(id)myMethodWithY:(int)Y withX:(int)X; + +@property (nonatomic, assign) NSString *text; +@end + +@implementation Test1 + +@synthesize text; + +-(id)myMethod { + Test1 *cell = [[[Test1 alloc] init] autorelease]; + + NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // No warning: this function is not analized. + cell.text = string1; + + return cell; +} + +-(id)myMethodWithY:(int)Y withX:(int)X { + Test1 *cell = [[[Test1 alloc] init] autorelease]; + + NSString *string1 = [[NSString alloc] initWithFormat:@"test %f %d", 0.0, X+Y]; // expected-warning {{Potential leak}} + cell.text = string1; + + return cell; +} + +@end diff --git a/clang/test/Analysis/analyze_display_progress.c b/clang/test/Analysis/analyze_display_progress.c new file mode 100644 index 0000000..958ed00 --- /dev/null +++ b/clang/test/Analysis/analyze_display_progress.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s + +void f() {}; +void g() {}; +void h() {} + +// CHECK: analyze_display_progress.c f +// CHECK: analyze_display_progress.c g +// CHECK: analyze_display_progress.c h
\ No newline at end of file diff --git a/clang/test/Analysis/analyzer-stats.c b/clang/test/Analysis/analyzer-stats.c new file mode 100644 index 0000000..9eeaade --- /dev/null +++ b/clang/test/Analysis/analyzer-stats.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s + +int foo(); + +int test() { // expected-warning{{Total CFGBlocks}} + int a = 1; + a = 34 / 12; + + if (foo()) + return a; + + a /= 4; + return a; +} diff --git a/clang/test/Analysis/array-struct-region.c b/clang/test/Analysis/array-struct-region.c new file mode 100644 index 0000000..4b085c8 --- /dev/null +++ b/clang/test/Analysis/array-struct-region.c @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.deadcode.UnreachableCode -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.deadcode.UnreachableCode -analyzer-store=region -analyzer-constraints=range -verify %s + +int string_literal_init() { + char a[] = "abc"; + char b[2] = "abc"; // expected-warning{{too long}} + char c[5] = "abc"; + + if (a[1] != 'b') + return 0; // expected-warning{{never executed}} + if (b[1] != 'b') + return 0; // expected-warning{{never executed}} + if (c[1] != 'b') + return 0; // expected-warning{{never executed}} + + if (a[3] != 0) + return 0; // expected-warning{{never executed}} + if (c[3] != 0) + return 0; // expected-warning{{never executed}} + + if (c[4] != 0) + return 0; // expected-warning{{never executed}} + + return 42; +} + +void nested_compound_literals(int rad) { + int vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, // expected-warning 6 {{implicit conversion turns literal floating-point number into integer}} + {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; // expected-warning 6 {{implicit conversion turns literal floating-point number into integer}} + int a; + + for (a = 0; a < 6; ++a) { + vec[a][0] *= rad; // no-warning + vec[a][1] *= rad; // no-warning + } +} + +void nested_compound_literals_float(float rad) { + float vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, + {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; + int a; + + for (a = 0; a < 6; ++a) { + vec[a][0] *= rad; // no-warning + vec[a][1] *= rad; // no-warning + } +} diff --git a/clang/test/Analysis/array-struct.c b/clang/test/Analysis/array-struct.c new file mode 100644 index 0000000..c5bdb86 --- /dev/null +++ b/clang/test/Analysis/array-struct.c @@ -0,0 +1,178 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -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 = (int) 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 + (void)1; +} + +struct s3 p[1]; + +// Code from postgresql. +// Current cast logic of region store mistakenly leaves the final result region +// an ElementRegion of type 'char'. Then load a nonloc::SymbolVal from it and +// assigns to 'a'. +void f16(struct s3 *p) { + struct s3 a = *((struct s3*) ((char*) &p[0])); // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption.}} +} + +void inv(struct s1 *); + +// Invalidate the struct field. +void f17() { + struct s1 t; + int x; + inv(&t); + if (t.e.d) + x = 1; +} + +void read(char*); + +void f18() { + char *q; + char *p = (char *) __builtin_alloca(10); + read(p); + q = p; + q++; + if (*q) { // no-warning + } +} diff --git a/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp new file mode 100644 index 0000000..67a8f2e --- /dev/null +++ b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp @@ -0,0 +1,864 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s +// XPASS: * + +class A { +public: + A() {} + ~A() {} + operator int() const { return 1; } +}; + +extern const bool UV; + +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +void test_array() { + A a[2]; + A b[0]; +} + +void test_scope() { + A a; + { A c; + A d; + } + A b; +} + +void test_return() { + A a; + A b; + if (UV) return; + A c; +} + +void test_goto() { + A a; +l0: + A b; + { A a; + if (UV) goto l0; + if (UV) goto l1; + A b; + } +l1: + A c; +} + +void test_if_implicit_scope() { + A a; + if (A b = a) + A c; + else A c; +} + +void test_if_jumps() { + A a; + if (A b = a) { + A c; + if (UV) return; + A d; + } else { + A c; + if (UV) return; + A d; + } + A e; +} + +void test_while_implicit_scope() { + A a; + while (A b = a) + A c; +} + +void test_while_jumps() { + A a; + while (A b = a) { + A c; + if (UV) break; + if (UV) continue; + if (UV) return; + A d; + } + A e; +} + +void test_do_implicit_scope() { + do A a; + while (UV); +} + +void test_do_jumps() { + A a; + do { + A b; + if (UV) break; + if (UV) continue; + if (UV) return; + A c; + } while (UV); + A d; +} + +void test_switch_implicit_scope() { + A a; + switch (A b = a) + A c; +} + +void test_switch_jumps() { + A a; + switch (A b = a) { + case 0: { + A c; + if (UV) break; + if (UV) return; + A f; + } + case 1: + break; + } + A g; +} + +void test_for_implicit_scope() { + for (A a; A b = a; ) + A c; +} + +void test_for_jumps() { + A a; + for (A b; A c = b; ) { + A d; + if (UV) break; + if (UV) continue; + if (UV) return; + A e; + } + A f; +} + +void test_catch_const_ref() { + try { + } catch (const A& e) { + } +} + +void test_catch_copy() { + try { + } catch (A e) { + } +} + +// CHECK: [B1 (ENTRY)] +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B1 (ENTRY)] +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: 1 +// CHECK: 2: return [B1.1]; +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: a +// CHECK: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 5: const A &b = a; +// CHECK: 6: A() (CXXConstructExpr, class A) +// CHECK: 7: [B1.6] (BindTemporary) +// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B1.8] +// CHECK: 10: const A &c = A(); +// CHECK: 11: [B1.10].~A() (Implicit destructor) +// CHECK: 12: [B1.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A [2]) +// CHECK: 2: A a[2]; +// CHECK: 3: (CXXConstructExpr, class A [0]) +// CHECK: 4: A b[0]; +// CHECK: 5: [B1.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: (CXXConstructExpr, class A) +// CHECK: 4: A c; +// CHECK: 5: (CXXConstructExpr, class A) +// CHECK: 6: A d; +// CHECK: 7: [B1.6].~A() (Implicit destructor) +// CHECK: 8: [B1.4].~A() (Implicit destructor) +// CHECK: 9: (CXXConstructExpr, class A) +// CHECK: 10: A b; +// CHECK: 11: [B1.10].~A() (Implicit destructor) +// CHECK: 12: [B1.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B4 (ENTRY)] +// CHECK: Succs (1): B3 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B1.2].~A() (Implicit destructor) +// CHECK: 4: [B3.4].~A() (Implicit destructor) +// CHECK: 5: [B3.2].~A() (Implicit destructor) +// CHECK: Preds (1): B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: return; +// CHECK: 2: [B3.4].~A() (Implicit destructor) +// CHECK: 3: [B3.2].~A() (Implicit destructor) +// CHECK: Preds (1): B3 +// CHECK: Succs (1): B0 +// CHECK: [B3] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: (CXXConstructExpr, class A) +// CHECK: 4: A b; +// CHECK: 5: UV +// CHECK: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B3.6] +// CHECK: Preds (1): B4 +// CHECK: Succs (2): B2 B1 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (2): B1 B2 +// CHECK: [B8 (ENTRY)] +// CHECK: Succs (1): B7 +// CHECK: [B1] +// CHECK: l1: +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B1.2].~A() (Implicit destructor) +// CHECK: 4: [B6.2].~A() (Implicit destructor) +// CHECK: 5: [B7.2].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A b; +// CHECK: 3: [B2.2].~A() (Implicit destructor) +// CHECK: 4: [B6.4].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: [B6.4].~A() (Implicit destructor) +// CHECK: T: goto l1; +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: UV +// CHECK: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B4.2] +// CHECK: Preds (1): B6 +// CHECK: Succs (2): B3 B2 +// CHECK: [B5] +// CHECK: 1: [B6.4].~A() (Implicit destructor) +// CHECK: 2: [B6.2].~A() (Implicit destructor) +// CHECK: T: goto l0; +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B6 +// CHECK: [B6] +// CHECK: l0: +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A b; +// CHECK: 3: (CXXConstructExpr, class A) +// CHECK: 4: A a; +// CHECK: 5: UV +// CHECK: 6: [B6.5] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B6.6] +// CHECK: Preds (2): B7 B5 +// CHECK: Succs (2): B5 B4 +// CHECK: [B7] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B6 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B5 (ENTRY)] +// CHECK: Succs (1): B4 +// CHECK: [B1] +// CHECK: 1: [B4.6].~A() (Implicit destructor) +// CHECK: 2: [B4.2].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B2.2].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B3.2].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: a +// CHECK: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 5: [B4.4] (CXXConstructExpr, class A) +// CHECK: 6: A b = a; +// CHECK: 7: b +// CHECK: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B4.8].operator int +// CHECK: 10: [B4.9]() +// CHECK: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: if [B4.12] +// CHECK: Preds (1): B5 +// CHECK: Succs (2): B3 B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B9 (ENTRY)] +// CHECK: Succs (1): B8 +// CHECK: [B1] +// CHECK: 1: [B8.6].~A() (Implicit destructor) +// CHECK: 2: (CXXConstructExpr, class A) +// CHECK: 3: A e; +// CHECK: 4: [B1.3].~A() (Implicit destructor) +// CHECK: 5: [B8.2].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B5 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A d; +// CHECK: 3: [B2.2].~A() (Implicit destructor) +// CHECK: 4: [B4.2].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: return; +// CHECK: 2: [B4.2].~A() (Implicit destructor) +// CHECK: 3: [B8.6].~A() (Implicit destructor) +// CHECK: 4: [B8.2].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B0 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: UV +// CHECK: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B4.4] +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B3 B2 +// CHECK: [B5] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A d; +// CHECK: 3: [B5.2].~A() (Implicit destructor) +// CHECK: 4: [B7.2].~A() (Implicit destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B1 +// CHECK: [B6] +// CHECK: 1: return; +// CHECK: 2: [B7.2].~A() (Implicit destructor) +// CHECK: 3: [B8.6].~A() (Implicit destructor) +// CHECK: 4: [B8.2].~A() (Implicit destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B0 +// CHECK: [B7] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: UV +// CHECK: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B7.4] +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: a +// CHECK: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 5: [B8.4] (CXXConstructExpr, class A) +// CHECK: 6: A b = a; +// CHECK: 7: b +// CHECK: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B8.8].operator int +// CHECK: 10: [B8.9]() +// CHECK: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: if [B8.12] +// CHECK: Preds (1): B9 +// CHECK: Succs (2): B7 B4 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (3): B1 B3 B6 +// CHECK: [B6 (ENTRY)] +// CHECK: Succs (1): B5 +// CHECK: [B1] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: 2: [B5.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: a +// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B2.2] (CXXConstructExpr, class A) +// CHECK: 4: A b = a; +// CHECK: 5: b +// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 7: [B2.6].operator int +// CHECK: 8: [B2.7]() +// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: while [B2.10] +// CHECK: Preds (2): B3 B5 +// CHECK: Succs (2): B4 B1 +// CHECK: [B3] +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B2 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B4.2].~A() (Implicit destructor) +// CHECK: 4: [B2.4].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B3 +// CHECK: [B5] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B12 (ENTRY)] +// CHECK: Succs (1): B11 +// CHECK: [B1] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: 2: (CXXConstructExpr, class A) +// CHECK: 3: A e; +// CHECK: 4: [B1.3].~A() (Implicit destructor) +// CHECK: 5: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (2): B9 B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: a +// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B2.2] (CXXConstructExpr, class A) +// CHECK: 4: A b = a; +// CHECK: 5: b +// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 7: [B2.6].operator int +// CHECK: 8: [B2.7]() +// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: while [B2.10] +// CHECK: Preds (2): B3 B11 +// CHECK: Succs (2): B10 B1 +// CHECK: [B3] +// CHECK: Preds (2): B4 B7 +// CHECK: Succs (1): B2 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A d; +// CHECK: 3: [B4.2].~A() (Implicit destructor) +// CHECK: 4: [B10.2].~A() (Implicit destructor) +// CHECK: 5: [B2.4].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B3 +// CHECK: [B5] +// CHECK: 1: return; +// CHECK: 2: [B10.2].~A() (Implicit destructor) +// CHECK: 3: [B2.4].~A() (Implicit destructor) +// CHECK: 4: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B0 +// CHECK: [B6] +// CHECK: 1: UV +// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B6.2] +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B5 B4 +// CHECK: [B7] +// CHECK: 1: [B10.2].~A() (Implicit destructor) +// CHECK: 2: [B2.4].~A() (Implicit destructor) +// CHECK: T: continue; +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B3 +// CHECK: [B8] +// CHECK: 1: UV +// CHECK: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B8.2] +// CHECK: Preds (1): B10 +// CHECK: Succs (2): B7 B6 +// CHECK: [B9] +// CHECK: 1: [B10.2].~A() (Implicit destructor) +// CHECK: T: break; +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B1 +// CHECK: [B10] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: UV +// CHECK: 4: [B10.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B10.4] +// CHECK: Preds (1): B2 +// CHECK: Succs (2): B9 B8 +// CHECK: [B11] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: Preds (1): B12 +// CHECK: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (2): B1 B5 +// CHECK: [B4 (ENTRY)] +// CHECK: Succs (1): B2 +// CHECK: [B1] +// CHECK: 1: UV +// CHECK: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: do ... while [B1.2] +// CHECK: Preds (1): B2 +// CHECK: Succs (2): B3 B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: [B2.2].~A() (Implicit destructor) +// CHECK: Preds (2): B3 B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: Preds (1): B1 +// CHECK: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B12 (ENTRY)] +// CHECK: Succs (1): B11 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A d; +// CHECK: 3: [B1.2].~A() (Implicit destructor) +// CHECK: 4: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (2): B8 B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: UV +// CHECK: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: do ... while [B2.2] +// CHECK: Preds (2): B3 B6 +// CHECK: Succs (2): B10 B1 +// CHECK: [B3] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B3.2].~A() (Implicit destructor) +// CHECK: 4: [B9.2].~A() (Implicit destructor) +// CHECK: Preds (1): B5 +// CHECK: Succs (1): B2 +// CHECK: [B4] +// CHECK: 1: return; +// CHECK: 2: [B9.2].~A() (Implicit destructor) +// CHECK: 3: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (1): B5 +// CHECK: Succs (1): B0 +// CHECK: [B5] +// CHECK: 1: UV +// CHECK: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B5.2] +// CHECK: Preds (1): B7 +// CHECK: Succs (2): B4 B3 +// CHECK: [B6] +// CHECK: 1: [B9.2].~A() (Implicit destructor) +// CHECK: T: continue; +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B2 +// CHECK: [B7] +// CHECK: 1: UV +// CHECK: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B7.2] +// CHECK: Preds (1): B9 +// CHECK: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK: 1: [B9.2].~A() (Implicit destructor) +// CHECK: T: break; +// CHECK: Preds (1): B9 +// CHECK: Succs (1): B1 +// CHECK: [B9] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A b; +// CHECK: 3: UV +// CHECK: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B9.4] +// CHECK: Preds (2): B10 B11 +// CHECK: Succs (2): B8 B7 +// CHECK: [B10] +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B9 +// CHECK: [B11] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: Preds (1): B12 +// CHECK: Succs (1): B9 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (2): B1 B4 +// CHECK: [B4 (ENTRY)] +// CHECK: Succs (1): B2 +// CHECK: [B1] +// CHECK: 1: [B2.6].~A() (Implicit destructor) +// CHECK: 2: [B2.2].~A() (Implicit destructor) +// CHECK: Preds (2): B3 B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: a +// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 5: [B2.4] (CXXConstructExpr, class A) +// CHECK: 6: A b = a; +// CHECK: 7: b +// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B2.8].operator int +// CHECK: 10: [B2.9]() +// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: T: switch [B2.11] +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B3.2].~A() (Implicit destructor) +// CHECK: Succs (1): B1 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B9 (ENTRY)] +// CHECK: Succs (1): B2 +// CHECK: [B1] +// CHECK: 1: [B2.6].~A() (Implicit destructor) +// CHECK: 2: (CXXConstructExpr, class A) +// CHECK: 3: A g; +// CHECK: 4: [B1.3].~A() (Implicit destructor) +// CHECK: 5: [B2.2].~A() (Implicit destructor) +// CHECK: Preds (3): B3 B7 B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: a +// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 5: [B2.4] (CXXConstructExpr, class A) +// CHECK: 6: A b = a; +// CHECK: 7: b +// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B2.8].operator int +// CHECK: 10: [B2.9]() +// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: T: switch [B2.11] +// CHECK: Preds (1): B9 +// CHECK: Succs (3): B3 B8 +// CHECK: B1 +// CHECK: [B3] +// CHECK: case 1: +// CHECK: T: break; +// CHECK: Preds (2): B2 B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A f; +// CHECK: 3: [B4.2].~A() (Implicit destructor) +// CHECK: 4: [B8.2].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B3 +// CHECK: [B5] +// CHECK: 1: return; +// CHECK: 2: [B8.2].~A() (Implicit destructor) +// CHECK: 3: [B2.6].~A() (Implicit destructor) +// CHECK: 4: [B2.2].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B0 +// CHECK: [B6] +// CHECK: 1: UV +// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B6.2] +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B5 B4 +// CHECK: [B7] +// CHECK: 1: [B8.2].~A() (Implicit destructor) +// CHECK: T: break; +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B1 +// CHECK: [B8] +// CHECK: case 0: +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: UV +// CHECK: 4: [B8.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B8.4] +// CHECK: Preds (1): B2 +// CHECK: Succs (2): B7 B6 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (2): B1 B5 +// CHECK: [B6 (ENTRY)] +// CHECK: Succs (1): B5 +// CHECK: [B1] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: 2: [B5.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: a +// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B2.2] (CXXConstructExpr, class A) +// CHECK: 4: A b = a; +// CHECK: 5: b +// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 7: [B2.6].operator int +// CHECK: 8: [B2.7]() +// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: for (...; [B2.10]; ) +// CHECK: Preds (2): B3 B5 +// CHECK: Succs (2): B4 B1 +// CHECK: [B3] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B2 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A c; +// CHECK: 3: [B4.2].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B3 +// CHECK: [B5] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B12 (ENTRY)] +// CHECK: Succs (1): B11 +// CHECK: [B1] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: 2: [B11.4].~A() (Implicit destructor) +// CHECK: 3: (CXXConstructExpr, class A) +// CHECK: 4: A f; +// CHECK: 5: [B1.4].~A() (Implicit destructor) +// CHECK: 6: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (2): B9 B2 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: b +// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B2.2] (CXXConstructExpr, class A) +// CHECK: 4: A c = b; +// CHECK: 5: c +// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 7: [B2.6].operator int +// CHECK: 8: [B2.7]() +// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK: T: for (...; [B2.10]; ) +// CHECK: Preds (2): B3 B11 +// CHECK: Succs (2): B10 B1 +// CHECK: [B3] +// CHECK: 1: [B2.4].~A() (Implicit destructor) +// CHECK: Preds (2): B4 B7 +// CHECK: Succs (1): B2 +// CHECK: [B4] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A e; +// CHECK: 3: [B4.2].~A() (Implicit destructor) +// CHECK: 4: [B10.2].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B3 +// CHECK: [B5] +// CHECK: 1: return; +// CHECK: 2: [B10.2].~A() (Implicit destructor) +// CHECK: 3: [B2.4].~A() (Implicit destructor) +// CHECK: 4: [B11.4].~A() (Implicit destructor) +// CHECK: 5: [B11.2].~A() (Implicit destructor) +// CHECK: Preds (1): B6 +// CHECK: Succs (1): B0 +// CHECK: [B6] +// CHECK: 1: UV +// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B6.2] +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B5 B4 +// CHECK: [B7] +// CHECK: 1: [B10.2].~A() (Implicit destructor) +// CHECK: T: continue; +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B3 +// CHECK: [B8] +// CHECK: 1: UV +// CHECK: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B8.2] +// CHECK: Preds (1): B10 +// CHECK: Succs (2): B7 B6 +// CHECK: [B9] +// CHECK: 1: [B10.2].~A() (Implicit destructor) +// CHECK: T: break; +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B1 +// CHECK: [B10] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A d; +// CHECK: 3: UV +// CHECK: 4: [B10.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: if [B10.4] +// CHECK: Preds (1): B2 +// CHECK: Succs (2): B9 B8 +// CHECK: [B11] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A a; +// CHECK: 3: (CXXConstructExpr, class A) +// CHECK: 4: A b; +// CHECK: Preds (1): B12 +// CHECK: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (2): B1 B5 +// CHECK: [B3 (ENTRY)] +// CHECK: Succs (1): B0 +// CHECK: [B1] +// CHECK: T: try ... +// CHECK: Succs (2): B2 B0 +// CHECK: [B2] +// CHECK: catch (const A &e): +// CHECK: 1: catch (const A &e) { +// CHECK: } +// CHECK: Preds (1): B1 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (3): B2 B1 B3 +// CHECK: [B3 (ENTRY)] +// CHECK: Succs (1): B0 +// CHECK: [B1] +// CHECK: T: try ... +// CHECK: Succs (2): B2 B0 +// CHECK: [B2] +// CHECK: catch (A e): +// CHECK: 1: catch (A e) { +// CHECK: } +// CHECK: 2: [B2.1].~A() (Implicit destructor) +// CHECK: Preds (1): B1 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (3): B2 B1 B3 diff --git a/clang/test/Analysis/base-init.cpp b/clang/test/Analysis/base-init.cpp new file mode 100644 index 0000000..8fd7abc --- /dev/null +++ b/clang/test/Analysis/base-init.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify %s +// XFAIL: * + +class A { + int x; +public: + A(); + int getx() const { + return x; + } +}; + +A::A() : x(0) { +} + +class B : public A { + int y; +public: + B(); +}; + +B::B() { +} + +void f() { + B b; + if (b.getx() != 0) { + int *p = 0; + *p = 0; // no-warning + } +} diff --git a/clang/test/Analysis/blocks.m b/clang/test/Analysis/blocks.m new file mode 100644 index 0000000..7a604dd --- /dev/null +++ b/clang/test/Analysis/blocks.m @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +//===----------------------------------------------------------------------===// + +typedef __builtin_va_list va_list; +typedef unsigned int uint32_t; +typedef struct dispatch_queue_s *dispatch_queue_t; +typedef struct dispatch_queue_attr_s *dispatch_queue_attr_t; +typedef void (^dispatch_block_t)(void); +void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); +__attribute__((visibility("default"))) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__nothrow__)) dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); +typedef long dispatch_once_t; +void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); +typedef signed char BOOL; +typedef unsigned long 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 <NSObject> {} ++ (id)alloc; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; +- ( const char *)UTF8String; +- (id)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); +@end +@class NSString, NSData; +typedef struct cssm_sample {} CSSM_SAMPLEGROUP, *CSSM_SAMPLEGROUP_PTR; +typedef struct __aslclient *aslclient; +typedef struct __aslmsg *aslmsg; +aslclient asl_open(const char *ident, const char *facility, uint32_t opts); +int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5))); + +//===----------------------------------------------------------------------===// +// Begin actual test cases. +//===----------------------------------------------------------------------===// + +// test1 - This test case exposed logic that caused the analyzer to crash because of a memory bug +// in BlockDataRegion. It represents real code that contains two block literals. Eventually +// via IPA 'logQueue' and 'client' should be updated after the call to 'dispatch_once'. +void test1(NSString *format, ...) { + static dispatch_queue_t logQueue; + static aslclient client; + static dispatch_once_t pred; + do { + if (__builtin_expect(*(&pred), ~0l) != ~0l) + dispatch_once(&pred, ^{ + logQueue = dispatch_queue_create("com.mycompany.myproduct.asl", ((void*)0)); + client = asl_open(((void*)0), "com.mycompany.myproduct", 0); + }); + } while (0); + + va_list args; + __builtin_va_start(args, format); + + NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; + dispatch_async(logQueue, ^{ asl_log(client, ((void*)0), 4, "%s", [str UTF8String]); }); + [str release]; + + __builtin_va_end(args); +} + +// test2 - Test that captured variables that are uninitialized are flagged +// as such. +void test2() { + static int y = 0; + int x; + ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}} +} + +void test2_b() { + static int y = 0; + __block int x; + // This is also a bug, but should be found not by checking the value + // 'x' is bound at block creation. + ^{ y = x + 1; }(); // no-warning +} + +void test2_c() { + typedef void (^myblock)(void); + myblock f = ^() { f(); }; // expected-warning{{Variable 'f' is uninitialized when captured by block}} +}
\ No newline at end of file diff --git a/clang/test/Analysis/bool-assignment.cpp b/clang/test/Analysis/bool-assignment.cpp new file mode 100644 index 0000000..e573129 --- /dev/null +++ b/clang/test/Analysis/bool-assignment.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s + +// Test C++'s bool + +void test_cppbool_initialization(int y) { + if (y < 0) { + bool x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + bool x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + bool x = y; // no-warning +} + +void test_cppbool_assignment(int y) { + bool x = 0; // no-warning + if (y < 0) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + x = y; // no-warning +} + +// Test Objective-C's BOOL + +typedef signed char BOOL; + +void test_BOOL_initialization(int y) { + if (y < 0) { + BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + BOOL x = y; // no-warning +} + +void test_BOOL_assignment(int y) { + BOOL x = 0; // no-warning + if (y < 0) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + x = y; // no-warning +} + + +// Test MacTypes.h's Boolean + +typedef unsigned char Boolean; + +void test_Boolean_initialization(int y) { + if (y < 0) { + Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + Boolean x = y; // no-warning +} + +void test_Boolean_assignment(int y) { + Boolean x = 0; // no-warning + if (y < 0) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + x = y; // no-warning +} diff --git a/clang/test/Analysis/bool-assignment2.c b/clang/test/Analysis/bool-assignment2.c new file mode 100644 index 0000000..9de26cf --- /dev/null +++ b/clang/test/Analysis/bool-assignment2.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -std=c99 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s + +// Test stdbool.h's _Bool + +// Prior to C99, stdbool.h uses this typedef, but even in ANSI C mode, _Bool +// appears to be defined. + +// #if __STDC_VERSION__ < 199901L +// typedef int _Bool; +// #endif + +void test_stdbool_initialization(int y) { + if (y < 0) { + _Bool x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + _Bool x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + _Bool x = y; // no-warning +} + +void test_stdbool_assignment(int y) { + _Bool x = 0; // no-warning + if (y < 0) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + if (y > 1) { + x = y; // expected-warning {{Assignment of a non-Boolean value}} + return; + } + x = y; // no-warning +} diff --git a/clang/test/Analysis/bstring.c b/clang/test/Analysis/bstring.c new file mode 100644 index 0000000..833c917 --- /dev/null +++ b/clang/test/Analysis/bstring.c @@ -0,0 +1,430 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring.NullArg,experimental.unix.cstring.OutOfBounds,experimental.unix.cstring.BufferOverlap,experimental.unix.cstring.NotNullTerminated -analyzer-store=region -Wno-null-dereference -verify %s + +//===----------------------------------------------------------------------=== +// Declarations +//===----------------------------------------------------------------------=== + +// Some functions are so similar to each other that they follow the same code +// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is +// defined, make sure to use the variants instead to make sure they are still +// checked by the analyzer. + +// Some functions are implemented as builtins. These should be #defined as +// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. + +// Functions that have variants and are also available as builtins should be +// declared carefully! See memcpy() for an example. + +#ifdef USE_BUILTINS +# define BUILTIN(f) __builtin_ ## f +#else /* USE_BUILTINS */ +# define BUILTIN(f) f +#endif /* USE_BUILTINS */ + +typedef typeof(sizeof(int)) size_t; + +//===----------------------------------------------------------------------=== +// memcpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __memcpy_chk BUILTIN(__memcpy_chk) +void *__memcpy_chk(void *restrict s1, const void *restrict s2, size_t n, + size_t destlen); + +#define memcpy(a,b,c) __memcpy_chk(a,b,c,(size_t)-1) + +#else /* VARIANT */ + +#define memcpy BUILTIN(memcpy) +void *memcpy(void *restrict s1, const void *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void memcpy0 () { + char src[] = {1, 2, 3, 4}; + char dst[4] = {0}; + + memcpy(dst, src, 4); // no-warning + + if (memcpy(dst, src, 4) != dst) { + (void)*(char*)0; // no-warning + } + + if (dst[0] != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void memcpy1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}} +} + +void memcpy2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + memcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}} +} + +void memcpy3 () { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + memcpy(dst+1, src+2, 2); // no-warning +} + +void memcpy4 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}} +} + +void memcpy5() { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + memcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}} +} + +void memcpy6() { + int a[4] = {0}; + memcpy(a, a, 8); // expected-warning{{overlapping}} +} + +void memcpy7() { + int a[4] = {0}; + memcpy(a+2, a+1, 8); // expected-warning{{overlapping}} +} + +void memcpy8() { + int a[4] = {0}; + memcpy(a+1, a+2, 8); // expected-warning{{overlapping}} +} + +void memcpy9() { + int a[4] = {0}; + memcpy(a+2, a+1, 4); // no-warning + memcpy(a+1, a+2, 4); // no-warning +} + +void memcpy10() { + char a[4] = {0}; + memcpy(0, a, 4); // expected-warning{{Null pointer argument in call to memory copy function}} +} + +void memcpy11() { + char a[4] = {0}; + memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}} +} + +void memcpy12() { + char a[4] = {0}; + memcpy(0, a, 0); // no-warning +} + +void memcpy13() { + char a[4] = {0}; + memcpy(a, 0, 0); // no-warning +} + +void memcpy_unknown_size (size_t n) { + char a[4], b[4] = {1}; + if (memcpy(a, b, n) != a) + (void)*(char*)0; // no-warning +} + +void memcpy_unknown_size_warn (size_t n) { + char a[4]; + if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}} + (void)*(char*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// mempcpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __mempcpy_chk BUILTIN(__mempcpy_chk) +void *__mempcpy_chk(void *restrict s1, const void *restrict s2, size_t n, + size_t destlen); + +#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1) + +#else /* VARIANT */ + +#define mempcpy BUILTIN(mempcpy) +void *mempcpy(void *restrict s1, const void *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void mempcpy0 () { + char src[] = {1, 2, 3, 4}; + char dst[5] = {0}; + + mempcpy(dst, src, 4); // no-warning + + if (mempcpy(dst, src, 4) != &dst[4]) { + (void)*(char*)0; // no-warning + } + + if (dst[0] != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void mempcpy1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + mempcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}} +} + +void mempcpy2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + mempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}} +} + +void mempcpy3 () { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + mempcpy(dst+1, src+2, 2); // no-warning +} + +void mempcpy4 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + mempcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}} +} + +void mempcpy5() { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + mempcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}} +} + +void mempcpy6() { + int a[4] = {0}; + mempcpy(a, a, 8); // expected-warning{{overlapping}} +} + +void mempcpy7() { + int a[4] = {0}; + mempcpy(a+2, a+1, 8); // expected-warning{{overlapping}} +} + +void mempcpy8() { + int a[4] = {0}; + mempcpy(a+1, a+2, 8); // expected-warning{{overlapping}} +} + +void mempcpy9() { + int a[4] = {0}; + mempcpy(a+2, a+1, 4); // no-warning + mempcpy(a+1, a+2, 4); // no-warning +} + +void mempcpy10() { + char a[4] = {0}; + mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to memory copy function}} +} + +void mempcpy11() { + char a[4] = {0}; + mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}} +} + +void mempcpy12() { + char a[4] = {0}; + mempcpy(0, a, 0); // no-warning +} + +void mempcpy13() { + char a[4] = {0}; + mempcpy(a, 0, 0); // no-warning +} + +void mempcpy_unknown_size_warn (size_t n) { + char a[4]; + if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}} + (void)*(char*)0; // no-warning +} + +void mempcpy_unknownable_size (char *src, float n) { + char a[4]; + // This used to crash because we don't model floats. + mempcpy(a, src, (size_t)n); +} + +//===----------------------------------------------------------------------=== +// memmove() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __memmove_chk BUILTIN(__memmove_chk) +void *__memmove_chk(void *s1, const void *s2, size_t n, size_t destlen); + +#define memmove(a,b,c) __memmove_chk(a,b,c,(size_t)-1) + +#else /* VARIANT */ + +#define memmove BUILTIN(memmove) +void *memmove(void *s1, const void *s2, size_t n); + +#endif /* VARIANT */ + + +void memmove0 () { + char src[] = {1, 2, 3, 4}; + char dst[4] = {0}; + + memmove(dst, src, 4); // no-warning + + if (memmove(dst, src, 4) != dst) { + (void)*(char*)0; // no-warning + } + + if (dst[0] != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void memmove1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memmove(dst, src, 5); // expected-warning{{out-of-bound}} +} + +void memmove2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + memmove(dst, src, 4); // expected-warning{{overflow}} +} + +//===----------------------------------------------------------------------=== +// memcmp() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define bcmp BUILTIN(bcmp) +// __builtin_bcmp is not defined with const in Builtins.def. +int bcmp(/*const*/ void *s1, /*const*/ void *s2, size_t n); +#define memcmp bcmp + +#else /* VARIANT */ + +#define memcmp BUILTIN(memcmp) +int memcmp(const void *s1, const void *s2, size_t n); + +#endif /* VARIANT */ + + +void memcmp0 () { + char a[] = {1, 2, 3, 4}; + char b[4] = { 0 }; + + memcmp(a, b, 4); // no-warning +} + +void memcmp1 () { + char a[] = {1, 2, 3, 4}; + char b[10] = { 0 }; + + memcmp(a, b, 5); // expected-warning{{out-of-bound}} +} + +void memcmp2 () { + char a[] = {1, 2, 3, 4}; + char b[1] = { 0 }; + + memcmp(a, b, 4); // expected-warning{{out-of-bound}} +} + +void memcmp3 () { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, a, 4)) + (void)*(char*)0; // no-warning +} + +void memcmp4 (char *input) { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, input, 4)) + (void)*(char*)0; // expected-warning{{null}} +} + +void memcmp5 (char *input) { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, 0, 0)) // no-warning + (void)*(char*)0; // no-warning + if (memcmp(0, a, 0)) // no-warning + (void)*(char*)0; // no-warning + if (memcmp(a, input, 0)) // no-warning + (void)*(char*)0; // no-warning +} + +void memcmp6 (char *a, char *b, size_t n) { + int result = memcmp(a, b, n); + if (result != 0) + return; + if (n == 0) + (void)*(char*)0; // expected-warning{{null}} +} + +int memcmp7 (char *a, size_t x, size_t y, size_t n) { + // We used to crash when either of the arguments was unknown. + return memcmp(a, &a[x*y], n) + + memcmp(&a[x*y], a, n); +} + +//===----------------------------------------------------------------------=== +// bcopy() +//===----------------------------------------------------------------------=== + +#define bcopy BUILTIN(bcopy) +// __builtin_bcopy is not defined with const in Builtins.def. +void bcopy(/*const*/ void *s1, void *s2, size_t n); + + +void bcopy0 () { + char src[] = {1, 2, 3, 4}; + char dst[4] = {0}; + + bcopy(src, dst, 4); // no-warning + + if (dst[0] != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void bcopy1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + bcopy(src, dst, 5); // expected-warning{{out-of-bound}} +} + +void bcopy2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + bcopy(src, dst, 4); // expected-warning{{overflow}} +} diff --git a/clang/test/Analysis/casts.c b/clang/test/Analysis/casts.c new file mode 100644 index 0000000..8b88a2d --- /dev/null +++ b/clang/test/Analysis/casts.c @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s + +// Test if the 'storage' region gets properly initialized after it is cast to +// 'struct sockaddr *'. + +typedef unsigned char __uint8_t; +typedef unsigned int __uint32_t; +typedef __uint32_t __darwin_socklen_t; +typedef __uint8_t sa_family_t; +typedef __darwin_socklen_t socklen_t; +struct sockaddr { sa_family_t sa_family; }; +struct sockaddr_storage {}; + +void getsockname(); + +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: + ; + } +} + +struct s { + struct s *value; +}; + +void f1(struct s **pval) { + int *tbool = ((void*)0); + struct s *t = *pval; + pval = &(t->value); + tbool = (int *)pval; // use the cast-to type 'int *' to create element region. + char c = (unsigned char) *tbool; // Should use cast-to type to create symbol. + if (*tbool == -1) // here load the element region with the correct type 'int' + (void)3; +} + +void f2(const char *str) { + unsigned char ch, cl, *p; + + p = (unsigned char *)str; + ch = *p++; // use cast-to type 'unsigned char' to create element region. + cl = *p++; + if(!cl) + cl = 'a'; +} + +// Test cast VariableSizeArray to pointer does not crash. +void *memcpy(void *, void const *, unsigned long); +typedef unsigned char Byte; +void doit(char *data, int len) { + if (len) { + Byte buf[len]; + memcpy(buf, data, len); + } +} + +// PR 6013 and 6035 - Test that a cast of a pointer to long and then to int does not crash SValuator. +void pr6013_6035_test(void *p) { + unsigned int foo; + foo = ((long)(p)); + (void) foo; +} diff --git a/clang/test/Analysis/casts.m b/clang/test/Analysis/casts.m new file mode 100644 index 0000000..6f19211 --- /dev/null +++ b/clang/test/Analysis/casts.m @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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)(); +} + +// <radar://10087620> +// A cast from int onjective C property reference to int. +typedef signed char BOOL; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@interface NSObject <NSObject> {} - (id)init; @end +typedef enum { + EEOne, + EETwo +} RDR10087620Enum; +@interface RDR10087620 : NSObject { + RDR10087620Enum elem; +} +@property (readwrite, nonatomic) RDR10087620Enum elem; +@end + +static void +adium_media_ready_cb(RDR10087620 *InObj) +{ + InObj.elem |= EEOne; +} diff --git a/clang/test/Analysis/cfref_PR2519.c b/clang/test/Analysis/cfref_PR2519.c new file mode 100644 index 0000000..5292109 --- /dev/null +++ b/clang/test/Analysis/cfref_PR2519.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -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/clang/test/Analysis/cfref_rdar6080742.c b/clang/test/Analysis/cfref_rdar6080742.c new file mode 100644 index 0000000..ea4c3ee --- /dev/null +++ b/clang/test/Analysis/cfref_rdar6080742.c @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s + +// This test case was reported in <rdar:problem/6080742>. +// 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/clang/test/Analysis/check-deserialization.cpp b/clang/test/Analysis/check-deserialization.cpp new file mode 100644 index 0000000..2b0bce2 --- /dev/null +++ b/clang/test/Analysis/check-deserialization.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-pch -o %t %s +// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -analyze -analyzer-checker=core %s +// RUN: %clang_cc1 -include-pch %t -analyze -analyzer-checker=core -verify %s + +#ifndef HEADER +#define HEADER +// Header. + +void S1_method(); // This should not be deserialized. + + +#else +// Using the header. + +int test() { + int x = 0; + return 5/x; //expected-warning {{Division by zero}} +} + +#endif diff --git a/clang/test/Analysis/chroot.c b/clang/test/Analysis/chroot.c new file mode 100644 index 0000000..1948f48 --- /dev/null +++ b/clang/test/Analysis/chroot.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Chroot -analyzer-store region -verify %s + +extern int chroot(const char* path); +extern int chdir(const char* path); + +void foo(void) { +} + +void f1(void) { + chroot("/usr/local"); // root changed. + foo(); // expected-warning {{No call of chdir("/") immediately after chroot}} +} + +void f2(void) { + chroot("/usr/local"); // root changed. + chdir("/"); // enter the jail. + foo(); // no-warning +} + +void f3(void) { + chroot("/usr/local"); // root changed. + chdir("../"); // change working directory, still out of jail. + foo(); // expected-warning {{No call of chdir("/") immediately after chroot}} +} diff --git a/clang/test/Analysis/complex.c b/clang/test/Analysis/complex.c new file mode 100644 index 0000000..c118a61 --- /dev/null +++ b/clang/test/Analysis/complex.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s + +#include <stdint.h> + +void 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/clang/test/Analysis/concrete-address.c b/clang/test/Analysis/concrete-address.c new file mode 100644 index 0000000..f6c445e --- /dev/null +++ b/clang/test/Analysis/concrete-address.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s + +void foo() { + int *p = (int*) 0x10000; // Should not crash here. + *p = 3; +} diff --git a/clang/test/Analysis/constant-folding.c b/clang/test/Analysis/constant-folding.c new file mode 100644 index 0000000..e7a5705 --- /dev/null +++ b/clang/test/Analysis/constant-folding.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode -Wno-null-dereference -verify %s + +// Trigger a warning if the analyzer reaches this point in the control flow. +#define WARN ((void)*(char*)0) + +// There should be no warnings unless otherwise indicated. + +void testComparisons (int a) { + // Sema can already catch the simple comparison a==a, + // since that's usually a logic error (and not path-dependent). + int b = a; + if (!(b==a)) WARN; // expected-warning{{never executed}} + if (!(b>=a)) WARN; // expected-warning{{never executed}} + if (!(b<=a)) WARN; // expected-warning{{never executed}} + if (b!=a) WARN; // expected-warning{{never executed}} + if (b>a) WARN; // expected-warning{{never executed}} + if (b<a) WARN; // expected-warning{{never executed}} +} + +void testSelfOperations (int a) { + if ((a|a) != a) WARN; // expected-warning{{never executed}} + if ((a&a) != a) WARN; // expected-warning{{never executed}} + if ((a^a) != 0) WARN; // expected-warning{{never executed}} + if ((a-a) != 0) WARN; // expected-warning{{never executed}} +} + +void testIdempotent (int a) { + if ((a*1) != a) WARN; // expected-warning{{never executed}} + if ((a/1) != a) WARN; // expected-warning{{never executed}} + if ((a+0) != a) WARN; // expected-warning{{never executed}} + if ((a-0) != a) WARN; // expected-warning{{never executed}} + if ((a<<0) != a) WARN; // expected-warning{{never executed}} + if ((a>>0) != a) WARN; // expected-warning{{never executed}} + if ((a^0) != a) WARN; // expected-warning{{never executed}} + if ((a&(~0)) != a) WARN; // expected-warning{{never executed}} + if ((a|0) != a) WARN; // expected-warning{{never executed}} +} + +void testReductionToConstant (int a) { + if ((a*0) != 0) WARN; // expected-warning{{never executed}} + if ((a&0) != 0) WARN; // expected-warning{{never executed}} + if ((a|(~0)) != (~0)) WARN; // expected-warning{{never executed}} +} + +void testSymmetricIntSymOperations (int a) { + if ((2+a) != (a+2)) WARN; // expected-warning{{never executed}} + if ((2*a) != (a*2)) WARN; // expected-warning{{never executed}} + if ((2&a) != (a&2)) WARN; // expected-warning{{never executed}} + if ((2^a) != (a^2)) WARN; // expected-warning{{never executed}} + if ((2|a) != (a|2)) WARN; // expected-warning{{never executed}} +} + +void testAsymmetricIntSymOperations (int a) { + if (((~0) >> a) != (~0)) WARN; // expected-warning{{never executed}} + if ((0 >> a) != 0) WARN; // expected-warning{{never executed}} + if ((0 << a) != 0) WARN; // expected-warning{{never executed}} + + // Unsigned right shift shifts in zeroes. + if ((((unsigned)(~0)) >> ((unsigned) a)) != ((unsigned)(~0))) + WARN; // expected-warning{{}} +} + +void testLocations (char *a) { + char *b = a; + if (!(b==a)) WARN; // expected-warning{{never executed}} + if (!(b>=a)) WARN; // expected-warning{{never executed}} + if (!(b<=a)) WARN; // expected-warning{{never executed}} + if (b!=a) WARN; // expected-warning{{never executed}} + if (b>a) WARN; // expected-warning{{never executed}} + if (b<a) WARN; // expected-warning{{never executed}} + if (b-a) WARN; // expected-warning{{never executed}} +} diff --git a/clang/test/Analysis/coverage.c b/clang/test/Analysis/coverage.c new file mode 100644 index 0000000..73d78da --- /dev/null +++ b/clang/test/Analysis/coverage.c @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -analyzer-max-loop 4 -verify %s +#include "system-header-simulator.h" + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); + +static int another_function(int *y) { + if (*y > 0) + return *y; + return 0; +} + +static void function_which_doesnt_give_up(int **x) { + *x = 0; +} + +static void function_which_gives_up(int *x) { + for (int i = 0; i < 5; ++i) + (*x)++; +} + +static void function_which_gives_up_nested(int *x) { + function_which_gives_up(x); + for (int i = 0; i < 5; ++i) + (*x)++; +} + +static void function_which_doesnt_give_up_nested(int *x, int *y) { + *y = another_function(x); + function_which_gives_up(x); +} + +void coverage1(int *x) { + function_which_gives_up(x); + char *m = (char*)malloc(12); // expected-warning {{potential leak}} +} + +void coverage2(int *x) { + if (x) { + function_which_gives_up(x); + char *m = (char*)malloc(12);// expected-warning {{potential leak}} + } +} + +void coverage3(int *x) { + x++; + function_which_gives_up(x); + char *m = (char*)malloc(12);// expected-warning {{potential leak}} +} + +void coverage4(int *x) { + *x += another_function(x); + function_which_gives_up(x); + char *m = (char*)malloc(12);// expected-warning {{potential leak}} +} + +void coverage5(int *x) { + for (int i = 0; i<7; ++i) + function_which_gives_up(x); + // The root function gives up here. + char *m = (char*)malloc(12); // no-warning +} + +void coverage6(int *x) { + for (int i = 0; i<3; ++i) { + function_which_gives_up(x); + } + char *m = (char*)malloc(12); // expected-warning {{potential leak}} +} + +int coverage7_inline(int *i) { + function_which_doesnt_give_up(&i); + return *i; // expected-warning {{Dereference}} +} + +void coverage8(int *x) { + int y; + function_which_doesnt_give_up_nested(x, &y); + y = (*x)/y; // expected-warning {{Division by zero}} + char *m = (char*)malloc(12); // expected-warning {{potential leak}} +} + +void function_which_gives_up_settonull(int **x) { + *x = 0; + int y = 0; + for (int i = 0; i < 5; ++i) + y++; +} + +void coverage9(int *x) { + int y = 5; + function_which_gives_up_settonull(&x); + y = (*x); // no warning +} diff --git a/clang/test/Analysis/cstring-syntax-cxx.cpp b/clang/test/Analysis/cstring-syntax-cxx.cpp new file mode 100644 index 0000000..f8975ab --- /dev/null +++ b/clang/test/Analysis/cstring-syntax-cxx.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -verify %s + +// Ensure we don't crash on C++ declarations with special names. +struct X { + X(int i): i(i) {} + int i; +}; + +X operator+(X a, X b) { + return X(a.i + b.i); +} + +void test(X a, X b) { + X c = a + b; +} + diff --git a/clang/test/Analysis/cstring-syntax.c b/clang/test/Analysis/cstring-syntax.c new file mode 100644 index 0000000..64ecb67 --- /dev/null +++ b/clang/test/Analysis/cstring-syntax.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s + +typedef __SIZE_TYPE__ size_t; +char *strncat(char *, const char *, size_t); +size_t strlen (const char *s); + +void testStrncat(const char *src) { + char dest[10]; + strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - 1); // expected-warning {{Potential buffer overflow. Replace with 'sizeof(dest) - strlen(dest) - 1' or use a safer 'strlcat' API}} + strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest)); // expected-warning {{Potential buffer overflow. Replace with}} + strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest)); // expected-warning {{Potential buffer overflow. Replace with}} + strncat(dest, src, sizeof(src)); // expected-warning {{Potential buffer overflow. Replace with}} +} diff --git a/clang/test/Analysis/cxx-crashes.cpp b/clang/test/Analysis/cxx-crashes.cpp new file mode 100644 index 0000000..17fc74d --- /dev/null +++ b/clang/test/Analysis/cxx-crashes.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s + +int f1(char *dst) { + char *p = dst + 4; + char *q = dst + 3; + return !(q >= p); +} + +long f2(char *c) { + return long(c) & 1; +} + +bool f3() { + return !false; +} + +void *f4(int* w) { + return reinterpret_cast<void*&>(w); +} + +namespace { + +struct A { }; +struct B { + operator A() { return A(); } +}; + +A f(char *dst) { + B b; + return b; +} + +} + +namespace { + +struct S { + void *p; +}; + +void *f(S* w) { + return &reinterpret_cast<void*&>(*w); +} + +} + +namespace { + +struct C { + void *p; + static void f(); +}; + +void C::f() { } + +} diff --git a/clang/test/Analysis/dead-stores.c b/clang/test/Analysis/dead-stores.c new file mode 100644 index 0000000..b8d195d --- /dev/null +++ b/clang/test/Analysis/dead-stores.c @@ -0,0 +1,550 @@ +// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s +// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s +// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s + +void f1() { + int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}} + int abc=1; + long idx=abc+3*5; // expected-warning {{never read}} expected-warning{{unused variable 'idx'}} +} + +void f2(void *b) { + char *c = (char*)b; // no-warning + char *d = b+1; // expected-warning {{never read}} expected-warning{{unused variable 'd'}} + printf("%s", c); // expected-warning{{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} \ + // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}} +} + +int f(); + +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}} expected-warning{{unused variable 'p'}} + +} + +// +int f6() { + + int x = 4; + ++x; // no-warning + return 1; +} + +int f7(int *p) { + // This is allowed for defensive programming. + p = 0; // no-warning + return 1; +} + +int f7b(int *p) { + // This is allowed for defensive programming. + p = (0); // no-warning + return 1; +} + +int f7c(int *p) { + // This is allowed for defensive programming. + p = (void*) 0; // no-warning + return 1; +} + +int f7d(int *p) { + // This is allowed for defensive programming. + p = (void*) (0); // no-warning + return 1; +} + +// Don't warn for dead stores in nested expressions. We have yet +// to see a real bug in this scenario. +int f8(int *p) { + extern int *baz(); + if ((p = baz())) // no-warning + 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{{unused variable 'x'}} + return 1; +} +int f12b(int y) { + int x __attribute__((unused)) = y; // no-warning + return 1; +} +int f12c(int y) { + // Allow initialiation of scalar variables by parameters as a form of + // defensive programming. + int x = y; // no-warning + x = 1; + return x; +} + +// 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 <rdar://problem/6248086> +void f15(unsigned x, unsigned y) { + int count = x * y; // no-warning + int z[count]; // expected-warning{{unused variable 'z'}} +} + +// Don't warn for dead stores in nested expressions. We have yet +// to see a real bug in this scenario. +int f16(int x) { + x = x * 2; + x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{The left operand to '+' is always 0}} expected-warning{{The left operand to '*' is always 1}} + ? 5 : 8; + return x; +} + +// Self-assignments should not be flagged as dead stores. +void f17() { + int x = 1; + x = x; +} + +// <rdar://problem/6506065> +// 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}} + // unreachable. + do + x = 10; // no-warning + while (1); + return (x = 10); // no-warning +} + +int f18_a() { + int x = 0; // no-warning + return (x = 10); // no-warning +} + +void f18_b() { + int x = 0; // no-warning + if (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} +} + +void f18_c() { + int x = 0; + while (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} +} + +void f18_d() { + int x = 0; // no-warning + do + x = 10; // expected-warning{{Value stored to 'x' is never read}} + while (1); +} + +// 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) +} + +void halt() __attribute__((noreturn)); +int f21() { + int x = 4; + + x = x + 1; // expected-warning{{never read}} + if (1) { + halt(); + (void)x; + } + return 1; +} + +int j; +void f22() { + int x = 4; + int y1 = 4; + int y2 = 4; + int y3 = 4; + int y4 = 4; + int y5 = 4; + int y6 = 4; + int y7 = 4; + int y8 = 4; + int y9 = 4; + int y10 = 4; + int y11 = 4; + int y12 = 4; + int y13 = 4; + int y14 = 4; + int y15 = 4; + int y16 = 4; + int y17 = 4; + int y18 = 4; + int y19 = 4; + int y20 = 4; + + x = x + 1; // expected-warning{{never read}} + ++y1; + ++y2; + ++y3; + ++y4; + ++y5; + ++y6; + ++y7; + ++y8; + ++y9; + ++y10; + ++y11; + ++y12; + ++y13; + ++y14; + ++y15; + ++y16; + ++y17; + ++y18; + ++y19; + ++y20; + + switch (j) { + case 1: + if (0) + (void)x; + if (1) { + (void)y1; + return; + } + (void)x; + break; + case 2: + if (0) + (void)x; + else { + (void)y2; + return; + } + (void)x; + break; + case 3: + if (1) { + (void)y3; + return; + } else + (void)x; + (void)x; + break; + case 4: + 0 ? : ((void)y4, ({ return; })); + (void)x; + break; + case 5: + 1 ? : (void)x; + 0 ? (void)x : ((void)y5, ({ return; })); + (void)x; + break; + case 6: + 1 ? ((void)y6, ({ return; })) : (void)x; + (void)x; + break; + case 7: + (void)(0 && x); + (void)y7; + (void)(0 || (y8, ({ return; }), 1)); // expected-warning {{expression result unused}} + (void)x; + break; + case 8: + (void)(1 && (y9, ({ return; }), 1)); // expected-warning {{expression result unused}} + (void)x; + break; + case 9: + (void)(1 || x); + (void)y10; + break; + case 10: + while (0) { + (void)x; + } + (void)y11; + break; + case 11: + while (1) { + (void)y12; + } + (void)x; + break; + case 12: + do { + (void)y13; + } while (0); + (void)y14; + break; + case 13: + do { + (void)y15; + } while (1); + (void)x; + break; + case 14: + for (;;) { + (void)y16; + } + (void)x; + break; + case 15: + for (;1;) { + (void)y17; + } + (void)x; + break; + case 16: + for (;0;) { + (void)x; + } + (void)y18; + break; + case 17: + __builtin_choose_expr(0, (void)x, ((void)y19, ({ return; }))); + (void)x; + break; + case 19: + __builtin_choose_expr(1, ((void)y20, ({ return; })), (void)x); + (void)x; + break; + } +} + +void f23_aux(const char* s); +void f23(int argc, char **argv) { + int shouldLog = (argc > 1); // no-warning + ^{ + if (shouldLog) f23_aux("I did too use it!\n"); + else f23_aux("I shouldn't log. Wait.. d'oh!\n"); + }(); +} + +void f23_pos(int argc, char **argv) { + int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}} expected-warning{{unused variable 'shouldLog'}} + ^{ + f23_aux("I did too use it!\n"); + }(); +} + +void f24_A(int y) { + // FIXME: One day this should be reported as dead since 'z = x + y' is dead. + int x = (y > 2); // no-warning + ^ { + int z = x + y; // expected-warning{{Value stored to 'z' during its initialization is never read}} expected-warning{{unused variable 'z'}} + }(); +} + +void f24_B(int y) { + // FIXME: One day this should be reported as dead since 'x' is just overwritten. + __block int x = (y > 2); // no-warning + ^{ + // FIXME: This should eventually be a dead store since it is never read either. + x = 5; // no-warning + }(); +} + +int f24_C(int y) { + // FIXME: One day this should be reported as dead since 'x' is just overwritten. + __block int x = (y > 2); // no-warning + ^{ + x = 5; // no-warning + }(); + return x; +} + +int f24_D(int y) { + __block int x = (y > 2); // no-warning + ^{ + if (y > 4) + x = 5; // no-warning + }(); + return x; +} + +// This example shows that writing to a variable captured by a block means that it might +// not be dead. +int f25(int y) { + __block int x = (y > 2); + __block int z = 0; + void (^foo)() = ^{ z = x + y; }; + x = 4; // no-warning + foo(); + return z; +} + +// This test is mostly the same as 'f25', but shows that the heuristic of pruning out dead +// stores for variables that are just marked '__block' is overly conservative. +int f25_b(int y) { + // FIXME: we should eventually report a dead store here. + __block int x = (y > 2); + __block int z = 0; + x = 4; // no-warning + return z; +} + +int f26_nestedblocks() { + int z; + z = 1; + __block int y = 0; + ^{ + int k; + k = 1; // expected-warning{{Value stored to 'k' is never read}} + ^{ + y = z + 1; + }(); + }(); + return y; +} + +// The FOREACH macro in QT uses 'break' statements within statement expressions +// placed within the increment code of for loops. +void rdar8014335() { + for (int i = 0 ; i != 10 ; ({ break; })) { + for ( ; ; ({ ++i; break; })) ; + // Note that the next value stored to 'i' is never executed + // because the next statement to be executed is the 'break' + // in the increment code of the first loop. + i = i * 3; // expected-warning{{Value stored to 'i' is never read}} expected-warning{{The left operand to '*' is always 1}} + } +} + +// <rdar://problem/8320674> NullStmts followed by do...while() can lead to disconnected CFG +// +// This previously caused bogus dead-stores warnings because the body of the first do...while was +// disconnected from the entry of the function. +typedef struct { float r; float i; } s_rdar8320674; +typedef struct { s_rdar8320674 x[1]; } s2_rdar8320674; + +void rdar8320674(s_rdar8320674 *z, unsigned y, s2_rdar8320674 *st, int m) +{ + s_rdar8320674 * z2; + s_rdar8320674 * tw1 = st->x; + s_rdar8320674 t; + z2 = z + m; + do{ + ; ; + do{ (t).r = (*z2).r*(*tw1).r - (*z2).i*(*tw1).i; (t).i = (*z2).r*(*tw1).i + (*z2).i*(*tw1).r; }while(0); + tw1 += y; + do { (*z2).r=(*z).r-(t).r; (*z2).i=(*z).i-(t).i; }while(0); + do { (*z).r += (t).r; (*z).i += (t).i; }while(0); + ++z2; + ++z; + }while (--m); +} + +// Avoid dead stores resulting from an assignment (and use) being unreachable. +void rdar8405222_aux(int i); +void rdar8405222() { + const int show = 0; + int i = 0; + + if (show) + i = 5; // no-warning + + if (show) + rdar8405222_aux(i); +} + +// Look through chains of assignements, e.g.: int x = y = 0, when employing +// silencing heuristics. +int radar11185138_foo() { + int x, y; + x = y = 0; // expected-warning {{never read}} + return y; +} + +int rdar11185138_bar() { + int y; + int x = y = 0; // no-warning + x = 2; + y = 2; + return x + y; +} + +int *radar11185138_baz() { + int *x, *y; + x = y = 0; // no-warning + return y; +} + diff --git a/clang/test/Analysis/dead-stores.cpp b/clang/test/Analysis/dead-stores.cpp new file mode 100644 index 0000000..43d8796 --- /dev/null +++ b/clang/test/Analysis/dead-stores.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s + +//===----------------------------------------------------------------------===// +// Basic dead store checking (but in C++ mode). +//===----------------------------------------------------------------------===// + +int j; +void test1() { + int x = 4; + + x = x + 1; // expected-warning{{never read}} + + switch (j) { + case 1: + throw 1; + (void)x; + break; + } +} + +//===----------------------------------------------------------------------===// +// Dead store checking involving constructors. +//===----------------------------------------------------------------------===// + +class Test2 { + int &x; +public: + Test2(int &y) : x(y) {} + ~Test2() { ++x; } +}; + +int test2(int x) { + { Test2 a(x); } // no-warning + return x; +} + +//===----------------------------------------------------------------------===// +// Dead store checking involving CXXTemporaryExprs +//===----------------------------------------------------------------------===// + +namespace TestTemp { + template<typename _Tp> + class pencil { + public: + ~pencil() throw() {} + }; + template<typename _Tp, typename _Number2> struct _Row_base { + _Row_base(const pencil<_Tp>& x) {} + }; + template<typename _Tp, typename _Number2 = TestTemp::pencil<_Tp> > + class row : protected _Row_base<_Tp, _Number2> { + typedef _Row_base<_Tp, _Number2> _Base; + typedef _Number2 pencil_type; + public: + explicit row(const pencil_type& __a = pencil_type()) : _Base(__a) {} + }; +} + +void test2_b() { + TestTemp::row<const char*> x; // no-warning +} + +//===----------------------------------------------------------------------===// +// Test references. +//===----------------------------------------------------------------------===// + +void test3_a(int x) { + x = x + 1; // expected-warning{{never read}} +} + +void test3_b(int &x) { + x = x + 1; // no-warninge +} + +void test3_c(int x) { + int &y = x; + // Shows the limitation of dead stores tracking. The write is really + // dead since the value cannot escape the function. + ++y; // no-warning +} + +void test3_d(int &x) { + int &y = x; + ++y; // no-warning +} + +void test3_e(int &x) { + int &y = x; +} + +//===----------------------------------------------------------------------===// +// Dead stores involving 'new' +//===----------------------------------------------------------------------===// + +static void test_new(unsigned n) { + char **p = new char* [n]; // expected-warning{{never read}} +} + +//===----------------------------------------------------------------------===// +// Dead stores in namespaces. +//===----------------------------------------------------------------------===// + +namespace foo { + int test_4(int x) { + x = 2; // expected-warning{{Value stored to 'x' is never read}} + x = 2; + return x; + } +} + diff --git a/clang/test/Analysis/dead-stores.m b/clang/test/Analysis/dead-stores.m new file mode 100644 index 0000000..0834274 --- /dev/null +++ b/clang/test/Analysis/dead-stores.m @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %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 <NSObject> {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSValue : NSObject <NSCopying, NSCoding> - (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 <NSCoding> {} @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 <-> deadcode.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"])) {} +} + +// This test case was a false positive due to how clang models +// pointer types and ObjC object pointer types differently. Here +// we don't warn about a dead store because 'nil' is assigned to +// an object pointer for the sake of defensive programming. +void rdar_7631278(NSObject *x) { + x = ((void*)0); +} + +// This test case issuing a bogus warning for the declaration of 'isExec' +// because the compound statement for the @synchronized was being visited +// twice by the LiveVariables analysis. +BOOL baz_rdar8527823(); +void foo_rdar8527823(); +@interface RDar8527823 +- (void) bar_rbar8527823; +@end +@implementation RDar8527823 +- (void) bar_rbar8527823 +{ + @synchronized(self) { + BOOL isExec = baz_rdar8527823(); // no-warning + if (isExec) foo_rdar8527823(); + } +} +@end + +// Don't flag dead stores to assignments to self within a nested assignment. +@interface Rdar7947686 +- (id) init; +@end + +@interface Rdar7947686_B : Rdar7947686 +- (id) init; +@end + +@implementation Rdar7947686_B +- (id) init { + id x = (self = [super init]); // no-warning + return x; +} +@end + +// Don't flag dead stores when a variable is captured in a block used +// by a property access. +@interface RDar10591355 +@property (assign) int x; +@end + +RDar10591355 *rdar10591355_aux(); + +void rdar10591355() { + RDar10591355 *p = rdar10591355_aux(); + ^{ (void) p.x; }(); +} diff --git a/clang/test/Analysis/debug-CallGraph.c b/clang/test/Analysis/debug-CallGraph.c new file mode 100644 index 0000000..b7c7c8a --- /dev/null +++ b/clang/test/Analysis/debug-CallGraph.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s + +static void mmm(int y) { + if (y != 0) + y++; + y = y/0; +} + +static int foo(int x, int y) { + mmm(y); + if (x != 0) + x++; + return 5/x; +} + +void aaa() { + foo(1,2); +} + +// CHECK:--- Call graph Dump --- +// CHECK: Function: < root > calls: aaa diff --git a/clang/test/Analysis/default-analyze.m b/clang/test/Analysis/default-analyze.m new file mode 100644 index 0000000..82656b2 --- /dev/null +++ b/clang/test/Analysis/default-analyze.m @@ -0,0 +1,63 @@ +// RUN: %clang --analyze %s -o %t + +// Tests that some specific checkers are enabled by default. + +id foo(int x) { + id title; + switch (x) { + case 1: + title = @"foo"; // expected-warning {{never read}} + case 2: + title = @"bar"; + break; + default: + title = "@baz"; + break; + } + return title; +} + +// <rdar://problem/8808566> Static analyzer is wrong: NSWidth(imgRect) not understood as unconditional assignment +// +// Note: this requires inlining support. This previously issued a false positive use of +// uninitialized value when calling NSWidth. +typedef double CGFloat; + +struct CGPoint { + CGFloat x; + CGFloat y; +}; +typedef struct CGPoint CGPoint; + +struct CGSize { + CGFloat width; + CGFloat height; +}; +typedef struct CGSize CGSize; + +struct CGRect { + CGPoint origin; + CGSize size; +}; +typedef struct CGRect CGRect; + +typedef CGRect NSRect; +typedef CGSize NSSize; + +static __inline__ __attribute__((always_inline)) CGFloat NSWidth(NSRect aRect) { + return (aRect.size.width); +} + +static __inline__ __attribute__((always_inline)) CGFloat NSHeight(NSRect aRect) { + return (aRect.size.height); +} + +NSSize rdar880566_size(); + +double rdar8808566() { + NSRect myRect; + myRect.size = rdar880566_size(); + double x = NSWidth(myRect) + NSHeight(myRect); // no-warning + return x; +} + diff --git a/clang/test/Analysis/default-diagnostic-visitors.c b/clang/test/Analysis/default-diagnostic-visitors.c new file mode 100644 index 0000000..9cb9ba8 --- /dev/null +++ b/clang/test/Analysis/default-diagnostic-visitors.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=text -verify %s + +// This file is for testing enhanced diagnostics produced by the default BugReporterVisitors. + +int getPasswordAndItem() +{ + int err = 0; + int *password; // expected-note {{Variable 'password' declared without an initial value}} + if (password == 0) { // expected-warning {{The left operand of '==' is a garbage value}} // expected-note {{The left operand of '==' is a garbage value}} + err = *password; + } + return err; +} diff --git a/clang/test/Analysis/delegates.m b/clang/test/Analysis/delegates.m new file mode 100644 index 0000000..8f42b83 --- /dev/null +++ b/clang/test/Analysis/delegates.m @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -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 <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 <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (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 <NSCopying, NSMutableCopying, NSCoding> - (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. +//===----------------------------------------------------------------------===// + +// <rdar://problem/6062730> +// 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/clang/test/Analysis/derived-to-base.cpp b/clang/test/Analysis/derived-to-base.cpp new file mode 100644 index 0000000..f65b9db --- /dev/null +++ b/clang/test/Analysis/derived-to-base.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region %s + +class A { +protected: + int x; +}; + +class B : public A { +public: + void f(); +}; + +void B::f() { + x = 3; +} diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp new file mode 100644 index 0000000..d1261dc --- /dev/null +++ b/clang/test/Analysis/div-zero.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core.DivideZero -verify %s + +int fooPR10616 (int qX ) { + int a, c, d; + + d = (qX-1); + while ( d != 0 ) { + d = c - (c/d) * d; + } + + return (a % (qX-1)); // expected-warning {{Division by zero}} + +} diff --git a/clang/test/Analysis/domtest.c b/clang/test/Analysis/domtest.c new file mode 100644 index 0000000..245186a --- /dev/null +++ b/clang/test/Analysis/domtest.c @@ -0,0 +1,165 @@ +// RUN: %clang -cc1 -analyze -analyzer-checker=debug.DumpDominators %s 2>&1 | FileCheck %s + +// Test the DominatorsTree implementation with various control flows +int test1() +{ + int x = 6; + int y = x/2; + int z; + + while(y > 0) { + if(y < x) { + x = x/y; + y = y-1; + }else{ + z = x - y; + } + x = x - 1; + x = x - 1; + } + z = x+y; + z = 3; + return 0; +} + +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK: (0,1) +// CHECK: (1,2) +// CHECK: (2,8) +// CHECK: (3,4) +// CHECK: (4,7) +// CHECK: (5,7) +// CHECK: (6,7) +// CHECK: (7,2) +// CHECK: (8,9) +// CHECK: (9,9) + +int test2() +{ + int x,y,z; + + x = 10; y = 100; + if(x > 0){ + y = 1; + }else{ + while(x<=0){ + x++; + y++; + } + } + z = y; + + return 0; +} + +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK: (0,1) +// CHECK: (1,6) +// CHECK: (2,6) +// CHECK: (3,4) +// CHECK: (4,2) +// CHECK: (5,6) +// CHECK: (6,7) +// CHECK: (7,7) + +int test3() +{ + int x,y,z; + + x = y = z = 1; + if(x>0) { + while(x>=0){ + while(y>=x) { + x = x-1; + y = y/2; + } + } + } + z = y; + + return 0; +} + +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK: (0,1) +// CHECK: (1,7) +// CHECK: (2,7) +// CHECK: (3,4) +// CHECK: (4,2) +// CHECK: (5,6) +// CHECK: (6,4) +// CHECK: (7,8) +// CHECK: (8,8) + +int test4() +{ + int y = 3; + while(y > 0) { + if(y < 3) { + while(y>0) + y ++; + }else{ + while(y<10) + y ++; + } + } + return 0; +} + +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK: (0,1) +// CHECK: (1,2) +// CHECK: (2,11) +// CHECK: (3,10) +// CHECK: (4,10) +// CHECK: (5,6) +// CHECK: (6,4) +// CHECK: (7,10) +// CHECK: (8,9) +// CHECK: (9,7) +// CHECK: (10,2) +// CHECK: (11,12) +// CHECK: (12,12) + +int test5() +{ + int x,y,z,a,b,c; + x = 1; + y = 2; + z = 3; + a = 4; + b = 5; + c = 6; + if ( x < 10 ) { + if ( y < 10 ) { + if ( z < 10 ) { + x = 4; + } else { + x = 5; + } + a = 10; + } else { + x = 6; + } + b = 10; + } else { + x = 7; + } + c = 11; + return 0; +} + +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK: (0,1) +// CHECK: (1,10) +// CHECK: (2,10) +// CHECK: (3,9) +// CHECK: (4,9) +// CHECK: (5,8) +// CHECK: (6,8) +// CHECK: (7,8) +// CHECK: (8,9) +// CHECK: (9,10) +// CHECK: (10,11) +// CHECK: (11,11) + diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp new file mode 100644 index 0000000..8d63cc4 --- /dev/null +++ b/clang/test/Analysis/dtor.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -verify %s + +class A { +public: + ~A() { + int *x = 0; + *x = 3; // expected-warning{{Dereference of null pointer}} + } +}; + +int main() { + A a; +} diff --git a/clang/test/Analysis/dtors-in-dtor-cfg-output.cpp b/clang/test/Analysis/dtors-in-dtor-cfg-output.cpp new file mode 100644 index 0000000..68ba37e --- /dev/null +++ b/clang/test/Analysis/dtors-in-dtor-cfg-output.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s +// XPASS: * + +class A { +public: + ~A() {} +}; + +class B : public virtual A { +public: + ~B() {} +}; + +class C : public virtual A { +public: + ~C() {} +}; + +class TestOrder : public C, public B, public virtual A { + A a; + int i; + A *p; +public: + ~TestOrder(); +}; + +TestOrder::~TestOrder() {} + +class TestArray { + A a[2]; + A b[0]; +public: + ~TestArray(); +}; + +TestArray::~TestArray() {} + +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: this->a.~A() (Member object destructor) +// CHECK: 2: ~B() (Base object destructor) +// CHECK: 3: ~C() (Base object destructor) +// CHECK: 4: ~A() (Base object destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: this->a.~A() (Member object destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 diff --git a/clang/test/Analysis/dynamic-cast.cpp b/clang/test/Analysis/dynamic-cast.cpp new file mode 100644 index 0000000..8e63b2b --- /dev/null +++ b/clang/test/Analysis/dynamic-cast.cpp @@ -0,0 +1,230 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core -verify %s + +class A { +public: + virtual void f(){}; + +}; +class B : public A{ +public: + int m; +}; +class C : public A{}; + +class BB: public B{}; + +// A lot of the tests below have the if statement in them, which forces the +// analyzer to explore both path - when the result is 0 and not. This makes +// sure that we definitely know that the result is non-0 (as the result of +// the cast). +int testDynCastFromRadar() { + B aa; + A *a = &aa; + const int* res = 0; + B *b = dynamic_cast<B*>(a); + static const int i = 5; + if(b) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testBaseToBase1() { + B b; + B *pb = &b; + B *pbb = dynamic_cast<B*>(pb); + const int* res = 0; + static const int i = 5; + if (pbb) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testMultipleLevelsOfSubclassing1() { + BB bb; + B *pb = &bb; + A *pa = pb; + B *b = dynamic_cast<B*>(pa); + const int* res = 0; + static const int i = 5; + if (b) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testMultipleLevelsOfSubclassing2() { + BB bb; + A *pbb = &bb; + B *b = dynamic_cast<B*>(pbb); + BB *s = dynamic_cast<BB*>(b); + const int* res = 0; + static const int i = 5; + if (s) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testMultipleLevelsOfSubclassing3() { + BB bb; + A *pbb = &bb; + B *b = dynamic_cast<B*>(pbb); + return b->m; // no warning +} + +int testLHS() { + B aa; + A *a = &aa; + return (dynamic_cast<B*>(a))->m; +} + +int testLHS2() { + B aa; + A *a = &aa; + return (*dynamic_cast<B*>(a)).m; +} + +int testDynCastUnknown2(class A *a) { + B *b = dynamic_cast<B*>(a); + return b->m; // no warning +} + +int testDynCastUnknown(class A *a) { + B *b = dynamic_cast<B*>(a); + const int* res = 0; + static const int i = 5; + if (b) { + res = &i; + } else { + res = 0; + } + return *res; // expected-warning {{Dereference of null pointer}} +} + +int testDynCastFail2() { + C c; + A *pa = &c; + B *b = dynamic_cast<B*>(pa); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testLHSFail() { + C c; + A *a = &c; + return (*dynamic_cast<B*>(a)).m; // expected-warning {{Dereference of null pointer}} +} + +int testBaseToDerivedFail() { + A a; + B *b = dynamic_cast<B*>(&a); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testConstZeroFail() { + B *b = dynamic_cast<B*>((A *)0); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testConstZeroFail2() { + A *a = 0; + B *b = dynamic_cast<B*>(a); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testUpcast() { + B b; + A *a = dynamic_cast<A*>(&b); + const int* res = 0; + static const int i = 5; + if (a) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testCastToVoidStar() { + A a; + void *b = dynamic_cast<void*>(&a); + const int* res = 0; + static const int i = 5; + if (b) { + res = &i; + } else { + res = 0; + } + return *res; // no warning +} + +int testReferenceSuccesfulCast() { + B rb; + B &b = dynamic_cast<B&>(rb); + int *x = 0; + return *x; // expected-warning {{Dereference of null pointer}} +} + +int testReferenceFailedCast() { + A a; + B &b = dynamic_cast<B&>(a); + int *x = 0; + return *x; // no warning (An exception is thrown by the cast.) +} + +// Here we allow any outcome of the cast and this is good because there is a +// situation where this will fail. So if the user has written the code in this +// way, we assume they expect the cast to succeed. +// Note, this might need special handling if we track types of symbolic casts +// and use them for dynamic_cast handling. +int testDynCastMostLikelyWillFail(C *c) { + B *b = 0; + b = dynamic_cast<B*>(c); + const int* res = 0; + static const int i = 5; + if (b) { + res = &i; + } else { + res = 0; + } + return *res; // expected-warning{{Dereference of null pointer}} +} + +class M : public B, public C {}; +void callTestDynCastMostLikelyWillFail() { + M m; + testDynCastMostLikelyWillFail(&m); +} + +// False positives/negatives. + +// Due to symbolic regions not being typed. +int testDynCastFalsePositive(BB *c) { + B *b = 0; + b = dynamic_cast<B*>(c); + const int* res = 0; + static const int i = 5; + if (b) { + res = &i; + } else { + res = 0; + } + return *res; // expected-warning{{Dereference of null pointer}} +} + +// Does not work when we new an object. +int testDynCastFail3() { + A *a = new A(); + B *b = dynamic_cast<B*>(a); + return b->m; +} + diff --git a/clang/test/Analysis/elementtype.c b/clang/test/Analysis/elementtype.c new file mode 100644 index 0000000..7452a0a --- /dev/null +++ b/clang/test/Analysis/elementtype.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region %s + +typedef struct added_obj_st { + int type; +} ADDED_OBJ; + +// Test if we are using the canonical type for ElementRegion. +void f() { + ADDED_OBJ *ao[4]={((void*)0),((void*)0),((void*)0),((void*)0)}; + if (ao[0] != ((void*)0)) { + ao[0]->type=0; + } +} diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c new file mode 100644 index 0000000..b592c33 --- /dev/null +++ b/clang/test/Analysis/exercise-ps.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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 void 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 library function 'memcpy' with type 'void *(void *, const void *}} \ + // expected-note{{please include the header <string.h> or explicitly provide a declaration for 'memcpy'}} +} diff --git a/clang/test/Analysis/fields.c b/clang/test/Analysis/fields.c new file mode 100644 index 0000000..2e72c77 --- /dev/null +++ b/clang/test/Analysis/fields.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %s -analyzer-store=region -verify + +unsigned foo(); +typedef struct bf { unsigned x:2; } bf; +void bar() { + bf y; + *(unsigned*)&y = foo(); + y.x = 1; +} + +struct s { + int n; +}; + +void f() { + struct s a; + int *p = &(a.n) + 1; +} + +typedef struct { + int x,y; +} Point; + +Point getit(void); +void test() { + Point p; + (void)(p = getit()).x; +} diff --git a/clang/test/Analysis/free.c b/clang/test/Analysis/free.c new file mode 100644 index 0000000..f688db7 --- /dev/null +++ b/clang/test/Analysis/free.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.unix.MallocWithAnnotations -fblocks -verify %s +void free(void *); + +void t1 () { + int a[] = { 1 }; + free(a); // expected-warning {{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}} +} + +void t2 () { + int a = 1; + free(&a); // expected-warning {{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}} +} + +void t3 () { + static int a[] = { 1 }; + free(a); // expected-warning {{Argument to free() is the address of the static variable 'a', which is not memory allocated by malloc()}} +} + +void t4 (char *x) { + free(x); // no-warning +} + +void t5 () { + extern char *ptr(); + free(ptr()); // no-warning +} + +void t6 () { + free((void*)1000); // expected-warning {{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}} +} + +void t7 (char **x) { + free(*x); // no-warning +} + +void t8 (char **x) { + // ugh + free((*x)+8); // no-warning +} + +void t9 () { +label: + free(&&label); // expected-warning {{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}} +} + +void t10 () { + free((void*)&t10); // expected-warning {{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} +} + +void t11 () { + char *p = (char*)__builtin_alloca(2); + free(p); // expected-warning {{Argument to free() was allocated by alloca(), not malloc()}} +} + +void t12 () { + free(^{return;}); // expected-warning {{Argument to free() is a block, which is not memory allocated by malloc()}} +} + +void t13 (char a) { + free(&a); // expected-warning {{Argument to free() is the address of the parameter 'a', which is not memory allocated by malloc()}} +} + +static int someGlobal[2]; +void t14 () { + free(someGlobal); // expected-warning {{Argument to free() is the address of the global variable 'someGlobal', which is not memory allocated by malloc()}} +} + +void t15 (char **x, int offset) { + // Unknown value + free(x[offset]); // no-warning +} diff --git a/clang/test/Analysis/func.c b/clang/test/Analysis/func.c new file mode 100644 index 0000000..b6cebde --- /dev/null +++ b/clang/test/Analysis/func.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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/clang/test/Analysis/global-region-invalidation.c b/clang/test/Analysis/global-region-invalidation.c new file mode 100644 index 0000000..184ffb8 --- /dev/null +++ b/clang/test/Analysis/global-region-invalidation.c @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest -verify %s + +// Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header. +#include "system-header-simulator.h" + +// Test that system header does not invalidate the internal global. +int size_rdar9373039 = 1; +int rdar9373039() { + int x; + int j = 0; + + for (int i = 0 ; i < size_rdar9373039 ; ++i) + x = 1; + + // strlen doesn't invalidate the value of 'size_rdar9373039'. + int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4)); + + for (int i = 0 ; i < size_rdar9373039 ; ++i) + j += x; // no-warning + + return j; +} + +// Test stdin does not get invalidated by a system call nor by an internal call. +void foo(); +int stdinTest() { + int i = 0; + fscanf(stdin, "%d", &i); + foo(); + int m = i; // expected-warning + {{tainted}} + fscanf(stdin, "%d", &i); + int j = i; // expected-warning + {{tainted}} + return m + j; // expected-warning + {{tainted}} +} + +// Test errno gets invalidated by a system call. +int testErrnoSystem() { + int i; + int *p = 0; + fscanf(stdin, "%d", &i); + if (errno == 0) { + fscanf(stdin, "%d", &i); // errno gets invalidated here. + return 5 / errno; // no-warning + } + return 0; +} + +// Test that errno gets invalidated by internal calls. +int testErrnoInternal() { + int i; + int *p = 0; + fscanf(stdin, "%d", &i); + if (errno == 0) { + foo(); // errno gets invalidated here. + return 5 / errno; // no-warning + } + return 0; +} + +// Test that const integer does not get invalidated. +const int x = 0; +int constIntGlob() { + const int *m = &x; + foo(); + return 3 / *m; // expected-warning {{Division by zero}} +} + +extern const int x; +int constIntGlobExtern() { + if (x == 0) { + foo(); + return 5 / x; // expected-warning {{Division by zero}} + } + return 0; +} diff --git a/clang/test/Analysis/html-diags-multifile.c b/clang/test/Analysis/html-diags-multifile.c new file mode 100644 index 0000000..611dd07 --- /dev/null +++ b/clang/test/Analysis/html-diags-multifile.c @@ -0,0 +1,17 @@ +// RUN: mkdir -p %t.dir +// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir +// RUN: ls %t.dir | grep report | count 0 +// RUN: rm -fR %t.dir +// REQUIRES: shell + +// This tests that we do not currently emit HTML diagnostics for reports that +// cross file boundaries. + +#include "html-diags-multifile.h" + +#define CALL_HAS_BUG(q) has_bug(q) + +void test_call_macro() { + CALL_HAS_BUG(0); +} + diff --git a/clang/test/Analysis/html-diags-multifile.h b/clang/test/Analysis/html-diags-multifile.h new file mode 100644 index 0000000..71d39ba --- /dev/null +++ b/clang/test/Analysis/html-diags-multifile.h @@ -0,0 +1,4 @@ +#define DEREF(p) *p = 0xDEADBEEF +void has_bug(int *p) { + DEREF(p); +} diff --git a/clang/test/Analysis/html-diags.c b/clang/test/Analysis/html-diags.c new file mode 100644 index 0000000..59d81a5 --- /dev/null +++ b/clang/test/Analysis/html-diags.c @@ -0,0 +1,20 @@ +// RUN: mkdir %t.dir +// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %T.dir %s +// RUN: rm -fR %t.dir + +// Currently this test mainly checks that the HTML diagnostics doesn't crash +// when handling macros will calls with macros. We should actually validate +// the output, but that requires being able to match against a specifically +// generate HTML file. + +#define DEREF(p) *p = 0xDEADBEEF + +void has_bug(int *p) { + DEREF(p); +} + +#define CALL_HAS_BUG(q) has_bug(q) + +void test_call_macro() { + CALL_HAS_BUG(0); +} diff --git a/clang/test/Analysis/idempotent-operations-limited-loops.c b/clang/test/Analysis/idempotent-operations-limited-loops.c new file mode 100644 index 0000000..71e7c27 --- /dev/null +++ b/clang/test/Analysis/idempotent-operations-limited-loops.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations %s -verify + +void always_warning() { int *p = 0; *p = 0xDEADBEEF; } // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} + +// This test case previously caused a bogus idempotent operation warning +// due to us not properly culling warnings due to incomplete analysis of loops. +int pr8403() +{ + int i; + for(i=0; i<10; i++) + { + int j; + for(j=0; j+1<i; j++) + { + } + } + return 0; +} + diff --git a/clang/test/Analysis/idempotent-operations.c b/clang/test/Analysis/idempotent-operations.c new file mode 100644 index 0000000..6cc9a01 --- /dev/null +++ b/clang/test/Analysis/idempotent-operations.c @@ -0,0 +1,236 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s + +// Basic tests + +extern void test(int i); +extern void test_f(float f); + +unsigned basic() { + int x = 10, zero = 0, one = 1; + + // x op x + x = x; // expected-warning {{Assigned value is always the same as the existing value}} + test(x - x); // expected-warning {{Both operands to '-' always have the same value}} + x -= x; // expected-warning {{Both operands to '-=' always have the same value}} + x = 10; // no-warning + test(x / x); // expected-warning {{Both operands to '/' always have the same value}} + x /= x; // expected-warning {{Both operands to '/=' always have the same value}} + x = 10; // no-warning + test(x & x); // expected-warning {{Both operands to '&' always have the same value}} + x &= x; // expected-warning {{Both operands to '&=' always have the same value}} + test(x | x); // expected-warning {{Both operands to '|' always have the same value}} + x |= x; // expected-warning {{Both operands to '|=' always have the same value}} + + // x op 1 + test(x * one); // expected-warning {{The right operand to '*' is always 1}} + x *= one; // expected-warning {{The right operand to '*=' is always 1}} + test(x / one); // expected-warning {{The right operand to '/' is always 1}} + x /= one; // expected-warning {{The right operand to '/=' is always 1}} + + // 1 op x + test(one * x); // expected-warning {{The left operand to '*' is always 1}} + + // x op 0 + test(x + zero); // expected-warning {{The right operand to '+' is always 0}} + test(x - zero); // expected-warning {{The right operand to '-' is always 0}} + test(x * zero); // expected-warning {{The right operand to '*' is always 0}} + test(x & zero); // expected-warning {{The right operand to '&' is always 0}} + test(x | zero); // expected-warning {{The right operand to '|' is always 0}} + test(x ^ zero); // expected-warning {{The right operand to '^' is always 0}} + test(x << zero); // expected-warning {{The right operand to '<<' is always 0}} + test(x >> zero); // expected-warning {{The right operand to '>>' is always 0}} + + // 0 op x + test(zero + x); // expected-warning {{The left operand to '+' is always 0}} + test(zero - x); // expected-warning {{The left operand to '-' is always 0}} + test(zero / x); // expected-warning {{The left operand to '/' is always 0}} + test(zero * x); // expected-warning {{The left operand to '*' is always 0}} + test(zero & x); // expected-warning {{The left operand to '&' is always 0}} + test(zero | x); // expected-warning {{The left operand to '|' is always 0}} + test(zero ^ x); // expected-warning {{The left operand to '^' is always 0}} + test(zero << x); // expected-warning {{The left operand to '<<' is always 0}} + test(zero >> x); // expected-warning {{The left operand to '>>' is always 0}} + + // Overwrite the values so these aren't marked as Pseudoconstants + x = 1; + zero = 2; + one = 3; + + return x + zero + one; +} + +void floats(float x) { + test_f(x * 1.0); // no-warning + test_f(x * 1.0F); // no-warning +} + +// Ensure that we don't report false poitives in complex loops +void bailout() { + int unused = 0, result = 4; + result = result; // expected-warning {{Assigned value is always the same as the existing value}} + + for (unsigned bg = 0; bg < 1024; bg ++) { + result = bg * result; // no-warning + + for (int i = 0; i < 256; i++) { + unused *= i; // no-warning + } + } +} + +// Relaxed liveness - check that we don't kill liveness at assignments +typedef unsigned uintptr_t; +void kill_at_assign() { + short array[2]; + uintptr_t x = (uintptr_t) array; + short *p = (short *) x; + + // The following branch should be infeasible. + if (!(p = &array[0])) { // expected-warning{{Assigned value is always the same as the existing value}} + p = 0; + *p = 1; // no-warning + } +} + +// False positive tests + +unsigned false1() { + int a = 10; + return a * (5 - 2 - 3); // no-warning +} + +enum testenum { enum1 = 0, enum2 }; +unsigned false2() { + int a = 1234; + return enum1 + a; // no-warning +} + +// Self assignments of unused variables are common false positives +unsigned false3(int param, int param2) { + param = param; // no-warning + + // if a self assigned variable is used later, then it should be reported still + param2 = param2; // expected-warning{{Assigned value is always the same as the existing value}} + + unsigned nonparam = 5; + + nonparam = nonparam; // expected-warning{{Assigned value is always the same as the existing value}} + + return param2 + nonparam; +} + +// Pseudo-constants (vars only read) and constants should not be reported +unsigned false4() { + // Trivial constant + const int height = 1; + int c = 42; + test(height * c); // no-warning + + // Pseudo-constant (never changes after decl) + int width = height; + + return width * 10; // no-warning +} + +// Block pseudoconstants +void false4a() { + // Pseudo-constant + __block int a = 1; + int b = 10; + __block int c = 0; + b *= a; // no-warning + + ^{ + // Psuedoconstant block var + test(b * c); // no-warning + + // Non-pseudoconstant block var + int d = 0; + test(b * d); // expected-warning{{The right operand to '*' is always 0}} + d = 5; + test(d); + }(); + + test(a + b); +} + +// Static vars are common false positives +int false5() { + static int test = 0; + int a = 56; + a *= test; // no-warning + test++; + return a; +} + +// Non-local storage vars are considered false positives +int globalInt = 1; +int false6() { + int localInt = 23; + + localInt /= globalInt; + + return localInt; +} + +// Check that assignments filter out false positives correctly +int false7() { + int zero = 0; // pseudo-constant + int one = 1; + + int a = 55; + a = a; // expected-warning{{Assigned value is always the same as the existing value}} + a = enum1 * a; // no-warning + + int b = 123; + b = b; // no-warning + + return a; +} + +// Check truncations do not flag as self-assignments +void false8() { + int a = 10000000; + a = (short)a; // no-warning + test(a); +} + +// This test case previously flagged a warning at 'b == c' because the +// analyzer previously allowed 'UnknownVal' as the index for ElementRegions. +typedef struct RDar8431728_F { + int RDar8431728_A; + unsigned char *RDar8431728_B; + int RDar8431728_E[6]; +} RDar8431728_D; +static inline int RDar8431728_C(RDar8431728_D * s, int n, + unsigned char **RDar8431728_B_ptr) { + int xy, wrap, pred, a, b, c; + + xy = s->RDar8431728_E[n]; + wrap = s->RDar8431728_A; + + a = s->RDar8431728_B[xy - 1]; + b = s->RDar8431728_B[xy - 1 - wrap]; + c = s->RDar8431728_B[xy - wrap]; + + if (b == c) { // no-warning + pred = a; + } else { + pred = c; + } + + *RDar8431728_B_ptr = &s->RDar8431728_B[xy]; + + return pred; +} + +// <rdar://problem/8601243> - Don't warn on pointer arithmetic. This +// is often idiomatic. +unsigned rdar8601243_aux(unsigned n); +void rdar8601243() { + char arr[100]; + char *start = arr; + start = start + rdar8601243_aux(sizeof(arr) - (arr - start)); // no-warning + (void) start; +} + diff --git a/clang/test/Analysis/idempotent-operations.cpp b/clang/test/Analysis/idempotent-operations.cpp new file mode 100644 index 0000000..51b5905 --- /dev/null +++ b/clang/test/Analysis/idempotent-operations.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s + +// C++ specific false positives + +extern void test(int i); +extern void test_ref(int &i); + +// Test references affecting pseudoconstants +void false1() { + int a = 0; + int five = 5; + int &b = a; + test(five * a); // expected-warning {{The right operand to '*' is always 0}} + b = 4; +} + +// Test not flagging idempotent operations because we aborted the analysis +// of a path because of an unsupported construct. +struct RDar9219143_Foo { + ~RDar9219143_Foo(); + operator bool() const; +}; + +RDar9219143_Foo foo(); +unsigned RDar9219143_bar(); +void RDar9219143_test() { + unsigned i, e; + for (i = 0, e = RDar9219143_bar(); i != e; ++i) + if (foo()) + break; + if (i == e) // no-warning + return; +} + diff --git a/clang/test/Analysis/idempotent-operations.m b/clang/test/Analysis/idempotent-operations.m new file mode 100644 index 0000000..9a9820c --- /dev/null +++ b/clang/test/Analysis/idempotent-operations.m @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s + +typedef signed char BOOL; +typedef unsigned long NSUInteger; +typedef struct _NSZone NSZone; +@protocol NSObject - (BOOL)isEqual:(id)object; +@end + +@interface NSObject {} + @property int locked; + @property(nonatomic, readonly) NSObject *media; +@end + +// <rdar://problem/8725041> - Don't flag idempotent operation warnings when +// a method may invalidate an instance variable. +@interface Rdar8725041 : NSObject { + id _attribute; +} + - (void) method2; +@end + +@implementation Rdar8725041 +- (BOOL) method1 { + BOOL needsUpdate = (BOOL)0; + id oldAttribute = _attribute; + [self method2]; + needsUpdate |= (_attribute != oldAttribute); // no-warning + return needsUpdate; +} + +- (void) method2 +{ + _attribute = ((void*)0); +} +@end + +// Test that the idempotent operations checker works in the prescence +// of property expressions. +void pr9116(NSObject *placeholder) { + int x = placeholder.media.locked = placeholder ? 1 : 0; +} + +// <rdar://problem/9130239>: Test that calling property setters doesn't +// trigger an assertion failure when the object is nil. +@interface RDar9130239 +@property (assign) id delegate; +@end + +void test_RDar9130239(RDar9130239 *x) { + if (x) + return; + x.delegate = x; // no-warning +} + diff --git a/clang/test/Analysis/initializer.cpp b/clang/test/Analysis/initializer.cpp new file mode 100644 index 0000000..656a8bf --- /dev/null +++ b/clang/test/Analysis/initializer.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -cfg-add-initializers -verify %s + +class A { + int x; +public: + A(); +}; + +A::A() : x(0) { + if (x != 0) { + int *p = 0; + *p = 0; // no-warning + } +} diff --git a/clang/test/Analysis/initializers-cfg-output.cpp b/clang/test/Analysis/initializers-cfg-output.cpp new file mode 100644 index 0000000..8a7a3f5 --- /dev/null +++ b/clang/test/Analysis/initializers-cfg-output.cpp @@ -0,0 +1,98 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-initializers %s 2>&1 | FileCheck %s +// XPASS: * + +class A { +public: + A() {} + A(int i) {} +}; + +class B : public virtual A { +public: + B() {} + B(int i) : A(i) {} +}; + +class C : public virtual A { +public: + C() {} + C(int i) : A(i) {} +}; + +class TestOrder : public C, public B, public A { + int i; + int& r; +public: + TestOrder(); +}; + +TestOrder::TestOrder() + : r(i), B(), i(), C() { + A a; +} + +class TestControlFlow { + int x, y, z; +public: + TestControlFlow(bool b); +}; + +TestControlFlow::TestControlFlow(bool b) + : y(b ? 0 : 1) + , x(0) + , z(y) { + int v; +} + +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: (CXXConstructExpr, class A) +// CHECK: 2: A([B1.1]) (Base initializer) +// CHECK: 3: (CXXConstructExpr, class C) +// CHECK: 4: C([B1.3]) (Base initializer) +// CHECK: 5: (CXXConstructExpr, class B) +// CHECK: 6: B([B1.5]) (Base initializer) +// CHECK: 7: (CXXConstructExpr, class A) +// CHECK: 8: A([B1.7]) (Base initializer) +// CHECK: 9: /*implicit*/int() +// CHECK: 10: i([B1.9]) (Member initializer) +// CHECK: 11: this +// CHECK: 12: [B1.11]->i +// CHECK: 13: r([B1.12]) (Member initializer) +// CHECK: 14: (CXXConstructExpr, class A) +// CHECK: 15: A a; +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B5 (ENTRY)] +// CHECK: Succs (1): B4 +// CHECK: [B1] +// CHECK: 1: [B4.4] ? [B2.1] : [B3.1] +// CHECK: 2: y([B1.1]) (Member initializer) +// CHECK: 3: this +// CHECK: 4: [B1.3]->y +// CHECK: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, int) +// CHECK: 6: z([B1.5]) (Member initializer) +// CHECK: 7: int v; +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: 0 +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: 1 +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: 0 +// CHECK: 2: x([B4.1]) (Member initializer) +// CHECK: 3: b +// CHECK: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK: T: [B4.4] ? ... : ... +// CHECK: Preds (1): B5 +// CHECK: Succs (2): B2 B3 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 diff --git a/clang/test/Analysis/inline-not-supported.c b/clang/test/Analysis/inline-not-supported.c new file mode 100644 index 0000000..bff0e4d --- /dev/null +++ b/clang/test/Analysis/inline-not-supported.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s + +// For now, don't inline varargs. +void foo(int *x, ...) { + *x = 1; +} + +void bar() { + foo(0, 2); // no-warning +} + +// For now, don't inline vararg blocks. +void (^baz)(int *x, ...) = ^(int *x, ...) { *x = 1; }; + +void taz() { + baz(0, 2); // no-warning +} + +// For now, don't inline blocks. +void (^qux)(int *p) = ^(int *p) { *p = 1; }; +void test_qux() { + qux(0); // no-warning +} + + +void test_analyzer_is_running() { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} +} diff --git a/clang/test/Analysis/inline-plist.c b/clang/test/Analysis/inline-plist.c new file mode 100644 index 0000000..549082d --- /dev/null +++ b/clang/test/Analysis/inline-plist.c @@ -0,0 +1,369 @@ +// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t +// RUN: FileCheck -input-file %t %s + +// <rdar://problem/10967815> +void mmm(int y) { + if (y != 0) + y++; +} + +int foo(int x, int y) { + mmm(y); + if (x != 0) + x++; + return 5/x; +} + +// Test a bug triggering only when inlined. +void has_bug(int *p) { + *p = 0xDEADBEEF; +} + +void test_has_bug() { + has_bug(0); +} + + +// CHECK: <?xml version="1.0" encoding="UTF-8"?> +// CHECK: <plist version="1.0"> +// CHECK: <dict> +// CHECK: <key>files</key> +// CHECK: <array> +// CHECK: </array> +// CHECK: <key>diagnostics</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'x' is equal to 0</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'x' is equal to 0</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Division by zero</string> +// CHECK: <key>message</key> +// CHECK: <string>Division by zero</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Division by zero</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Division by zero</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>foo</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'has_bug'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'has_bug'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>18</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'test_has_bug'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'test_has_bug'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>18</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>18</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>has_bug</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </plist> diff --git a/clang/test/Analysis/inline-unique-reports.c b/clang/test/Analysis/inline-unique-reports.c new file mode 100644 index 0000000..ae94267 --- /dev/null +++ b/clang/test/Analysis/inline-unique-reports.c @@ -0,0 +1,184 @@ +// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t > /dev/null 2>&1 +// RUN: FileCheck -input-file %t %s + +static inline bug(int *p) { + *p = 0xDEADBEEF; +} + +void test_bug_1() { + int *p = 0; + bug(p); +} + +void test_bug_2() { + int *p = 0; + bug(p); +} + +// CHECK: <?xml version="1.0" encoding="UTF-8"?> +// CHECK: <plist version="1.0"> +// CHECK: <dict> +// CHECK: <key>files</key> +// CHECK: <array> +// CHECK: </array> +// CHECK: <key>diagnostics</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>9</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>9</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'bug'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'bug'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>4</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'test_bug_1'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'test_bug_1'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>4</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>4</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>bug</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </plist> diff --git a/clang/test/Analysis/inline.c b/clang/test/Analysis/inline.c new file mode 100644 index 0000000..0827d93 --- /dev/null +++ b/clang/test/Analysis/inline.c @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s + +int test1_f1() { + int y = 1; + y++; + return y; +} + +void test1_f2() { + int x = 1; + x = test1_f1(); + if (x == 1) { + int *p = 0; + *p = 3; // no-warning + } + if (x == 2) { + int *p = 0; + *p = 3; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} + } +} + +// Test that inlining works when the declared function has less arguments +// than the actual number in the declaration. +void test2_f1() {} +int test2_f2(); + +void test2_f3() { + test2_f1(test2_f2()); // expected-warning{{too many arguments in call to 'test2_f1'}} +} + +// Test that inlining works with recursive functions. + +unsigned factorial(unsigned x) { + if (x <= 1) + return 1; + return x * factorial(x - 1); +} + +void test_factorial() { + if (factorial(3) == 6) { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + } + else { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } +} + +void test_factorial_2() { + unsigned x = factorial(3); + if (x == factorial(3)) { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + } + else { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } +} + +// Test that returning stack memory from a parent stack frame does +// not trigger a warning. +static char *return_buf(char *buf) { + return buf + 10; +} + +void test_return_stack_memory_ok() { + char stack_buf[100]; + char *pos = return_buf(stack_buf); + (void) pos; +} + +char *test_return_stack_memory_bad() { + char stack_buf[100]; + char *x = stack_buf; + return x; // expected-warning {{stack memory associated}} +} + +// Test that passing a struct value with an uninitialized field does +// not trigger a warning if we are inlining and the body is available. +struct rdar10977037 { int x, y; }; +int test_rdar10977037_aux(struct rdar10977037 v) { return v.y; } +int test_rdar10977037_aux_2(struct rdar10977037 v); +int test_rdar10977037() { + struct rdar10977037 v; + v.y = 1; + v. y += test_rdar10977037_aux(v); // no-warning + return test_rdar10977037_aux_2(v); // expected-warning {{Passed-by-value struct argument contains uninitialized data}} +} + + diff --git a/clang/test/Analysis/inline2.c b/clang/test/Analysis/inline2.c new file mode 100644 index 0000000..473146c --- /dev/null +++ b/clang/test/Analysis/inline2.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s + +// Test parameter 'a' is registered to LiveVariables analysis data although it +// is not referenced in the function body. +// Before processing 'return 1;', in RemoveDeadBindings(), we query the liveness +// of 'a', because we have a binding for it due to parameter passing. +int f1(int a) { + return 1; +} + +void f2() { + int x; + x = f1(1); +} diff --git a/clang/test/Analysis/inline3.c b/clang/test/Analysis/inline3.c new file mode 100644 index 0000000..968d82a --- /dev/null +++ b/clang/test/Analysis/inline3.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s + +// Test when entering f1(), we set the right AnalysisDeclContext to Environment. +// Otherwise, block-level expr '1 && a' would not be block-level. +int a; + +void f1() { + if (1 && a) + return; +} + +void f2() { + f1(); +} diff --git a/clang/test/Analysis/inline4.c b/clang/test/Analysis/inline4.c new file mode 100644 index 0000000..e7715e0 --- /dev/null +++ b/clang/test/Analysis/inline4.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s + +int g(int a) { + return a; +} + +int f(int a) { + // Do not remove block-level expression bindings of caller when analyzing + // in the callee. + if (1 && g(a)) // The binding of '1 && g(a)' which is an UndefinedVal + // carries important information. + return 1; + return 0; +} diff --git a/clang/test/Analysis/iterators.cpp b/clang/test/Analysis/iterators.cpp new file mode 100644 index 0000000..1b6340b --- /dev/null +++ b/clang/test/Analysis/iterators.cpp @@ -0,0 +1,105 @@ +// RUN: %clang --analyze -Xclang -analyzer-checker=core,experimental.cplusplus.Iterators -Xclang -verify %s +// XFAIL: win32 + +#include <vector> + +void fum(std::vector<int>::iterator t); + +void foo1() +{ + // iterators that are defined but not initialized + std::vector<int>::iterator it2; + fum(it2); // expected-warning{{Use of iterator that is not defined}} + *it2; // expected-warning{{Use of iterator that is not defined}} + + std::vector<int> v, vv; + std::vector<int>::iterator it = v.begin(); + fum(it); // no-warning + *it; // no-warning + // a valid iterator plus an integer is still valid + std::vector<int>::iterator et = it + 3; + while(it != et) { // no-warning + if (*it == 0) // no-warning + *it = 1; // no-warning + } + // iterators from different instances Cannot be compared + et = vv.end(); + while(it != et) // expected-warning{{Cannot compare iterators from different containers}} + ; + + for( std::vector<int>::iterator it = v.begin(); it != v.end(); it++ ) { // no-warning + if (*it == 1) // no-warning + *it = 0; // no-warning + } + + // copying a valid iterator results in a valid iterator + et = it; // no-warning + *et; // no-warning + + // any combo of valid iterator plus a constant is still valid + et = it + 2; // no-warning + *et; // no-warning + et = 2 + it; // no-warning + *et; // no-warning + et = 2 + 4 + it; // no-warning + *et; // no-warning + + // calling insert invalidates unless assigned to as result, but still + // invalidates other iterators on the same instance + it = v.insert( it, 1 ); // no-warning + *et; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} + ++it; // no-warning + + // calling erase invalidates the iterator + v.erase(it); // no-warning + et = it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + et = 2 + it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + et = 2 + it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + ++it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + it++; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} + // now valid after return from insert + *it; // no-warning +} + +// work with using namespace +void foo2() +{ + using namespace std; + + vector<int> v; + vector<int>::iterator it = v.begin(); + *it; // no-warning + v.insert( it, 1 ); // no-warning + *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} + it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} + *it; // no-warning +} + +// using reserve eliminates some warnings +void foo3() +{ + std::vector<long> v; + std::vector<long>::iterator b = v.begin(); + v.reserve( 100 ); + + // iterator assigned before the reserve is still invalidated + *b; // expected-warning{{Attempt to use an iterator made invalid by call to 'reserve'}} + b = v.begin(); + v.insert( b, 1 ); // no-warning + + // iterator after assignment is still valid (probably) + *b; // no-warning +} + +// check on copying one iterator to another +void foo4() +{ + std::vector<float> v, vv; + std::vector<float>::iterator it = v.begin(); + *it; // no-warning + v = vv; + *it; // expected-warning{{Attempt to use an iterator made invalid by copying another container to its container}} +} + diff --git a/clang/test/Analysis/keychainAPI-diagnostic-visitor.m b/clang/test/Analysis/keychainAPI-diagnostic-visitor.m new file mode 100644 index 0000000..a78b114 --- /dev/null +++ b/clang/test/Analysis/keychainAPI-diagnostic-visitor.m @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=osx.SecKeychainAPI -analyzer-store=region -analyzer-output=text -verify %s + +// This file is for testing enhanced diagnostics produced by the default SecKeychainAPI checker. + +typedef unsigned int OSStatus; +typedef unsigned int SecKeychainAttributeList; +typedef unsigned int SecKeychainItemRef; +typedef unsigned int SecItemClass; +typedef unsigned int UInt32; +enum { + noErr = 0, + GenericError = 1 +}; +OSStatus SecKeychainItemCopyContent ( + SecKeychainItemRef itemRef, + SecItemClass *itemClass, + SecKeychainAttributeList *attrList, + UInt32 *length, + void **outData + ); + +void DellocWithCFStringCreate4() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + char *bytes; + char *x; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, (void **)&bytes); // expected-note {{Data is allocated here}} + x = bytes; + if (st == noErr) // expected-note {{Assuming 'st' is equal to noErr}} // expected-note{{Taking true branch}} + x = bytes;; + + length++; // expected-warning {{Allocated data is not released}} // expected-note{{Allocated data is not released}} +} + diff --git a/clang/test/Analysis/keychainAPI.m b/clang/test/Analysis/keychainAPI.m new file mode 100644 index 0000000..cb4f72c --- /dev/null +++ b/clang/test/Analysis/keychainAPI.m @@ -0,0 +1,409 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-ipa=inlining -verify + +// Fake typedefs. +typedef unsigned int OSStatus; +typedef unsigned int SecKeychainAttributeList; +typedef unsigned int SecKeychainItemRef; +typedef unsigned int SecItemClass; +typedef unsigned int UInt32; +typedef unsigned int CFTypeRef; +typedef unsigned int UInt16; +typedef unsigned int SecProtocolType; +typedef unsigned int SecAuthenticationType; +typedef unsigned int SecKeychainAttributeInfo; +enum { + noErr = 0, + GenericError = 1 +}; + +// Functions that allocate data. +OSStatus SecKeychainItemCopyContent ( + SecKeychainItemRef itemRef, + SecItemClass *itemClass, + SecKeychainAttributeList *attrList, + UInt32 *length, + void **outData +); +OSStatus SecKeychainFindGenericPassword ( + CFTypeRef keychainOrArray, + UInt32 serviceNameLength, + const char *serviceName, + UInt32 accountNameLength, + const char *accountName, + UInt32 *passwordLength, + void **passwordData, + SecKeychainItemRef *itemRef +); +OSStatus SecKeychainFindInternetPassword ( + CFTypeRef keychainOrArray, + UInt32 serverNameLength, + const char *serverName, + UInt32 securityDomainLength, + const char *securityDomain, + UInt32 accountNameLength, + const char *accountName, + UInt32 pathLength, + const char *path, + UInt16 port, + SecProtocolType protocol, + SecAuthenticationType authenticationType, + UInt32 *passwordLength, + void **passwordData, + SecKeychainItemRef *itemRef +); +OSStatus SecKeychainItemCopyAttributesAndData ( + SecKeychainItemRef itemRef, + SecKeychainAttributeInfo *info, + SecItemClass *itemClass, + SecKeychainAttributeList **attrList, + UInt32 *length, + void **outData +); + +// Functions which free data. +OSStatus SecKeychainItemFreeContent ( + SecKeychainAttributeList *attrList, + void *data +); +OSStatus SecKeychainItemFreeAttributesAndData ( + SecKeychainAttributeList *attrList, + void *data +); + +void errRetVal() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + if (st == GenericError) // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}} + SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}} +} + +// If null is passed in, the data is not allocated, so no need for the matching free. +void fooDoNotReportNull() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 *length = 0; + void **outData = 0; + SecKeychainItemCopyContent(2, ptr, ptr, 0, 0); + SecKeychainItemCopyContent(2, ptr, ptr, length, outData); +}// no-warning + +void doubleAlloc() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}} + if (st == noErr) + SecKeychainItemFreeContent(ptr, outData); +} + +void fooOnlyFree() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData = &length; + SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}} +} + +// Do not warn if undefined value is passed to a function. +void fooOnlyFreeUndef() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + SecKeychainItemFreeContent(ptr, outData); +}// no-warning + +// Do not warn if the address is a parameter in the enclosing function. +void fooOnlyFreeParam(void *attrList, void* X) { + SecKeychainItemFreeContent(attrList, X); +}// no-warning + +// If we are returning the value, do not report. +void* returnContent() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + return outData; +} // no-warning + +// Password was passed in as an argument and does not have to be deleted. +OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) { + OSStatus err; + SecKeychainItemRef item; + err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", + passwordLength, password, &item); + return err; +} // no-warning + +// Make sure we do not report an error if we call free only if password != 0. +// Also, do not report double allocation if first allocation returned an error. +OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength, + CFTypeRef keychainOrArray, SecProtocolType protocol, + SecAuthenticationType authenticationType) { + OSStatus err; + SecKeychainItemRef item; + void *password; + err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", + passwordLength, &password, &item); + if( err == GenericError ) { + err = SecKeychainFindInternetPassword(keychainOrArray, + 16, "server", 16, "domain", 16, "account", + 16, "path", 222, protocol, authenticationType, + passwordLength, &(password), 0); + } + + if (err == noErr && password) { + SecKeychainItemFreeContent(0, password); + } + return err; +} + +int apiMismatch(SecKeychainItemRef itemRef, + SecKeychainAttributeInfo *info, + SecItemClass *itemClass) { + OSStatus st = 0; + SecKeychainAttributeList *attrList; + UInt32 length; + void *outData; + + st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, + &attrList, &length, &outData); + if (st == noErr) + SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}} + return 0; +} + +int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, + SecKeychainAttributeInfo *info, + SecItemClass *itemClass) { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + OSStatus st2 = 0; + SecKeychainAttributeList *attrList; + UInt32 length2; + void *outData2; + + st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, + &attrList, &length2, &outData2); + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + if (st == noErr) { + SecKeychainItemFreeContent(ptr, outData); + if (st2 == noErr) { + SecKeychainItemFreeAttributesAndData(attrList, outData2); + } + } + return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}} +} + +int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, + SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { + unsigned int *ptr = 0; + OSStatus st = 0; + + UInt32 length; + void *outData[5]; + + st = SecKeychainFindInternetPassword(keychainOrArray, + 16, "server", 16, "domain", 16, "account", + 16, "path", 222, protocol, authenticationType, + &length, &(outData[3]), itemRef); + if (length == 5) { + if (st == noErr) + SecKeychainItemFreeContent(ptr, outData[3]); + } + if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}} + length++; + } + return 0; +}// no-warning + +void free(void *ptr); +void deallocateWithFree() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + if (st == noErr) + free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}} +} + +// Typesdefs for CFStringCreateWithBytesNoCopy. +typedef char uint8_t; +typedef signed long CFIndex; +typedef UInt32 CFStringEncoding; +typedef unsigned Boolean; +typedef const struct __CFString * CFStringRef; +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern const CFAllocatorRef kCFAllocatorSystemDefault; +extern const CFAllocatorRef kCFAllocatorMalloc; +extern const CFAllocatorRef kCFAllocatorMallocZone; +extern const CFAllocatorRef kCFAllocatorNull; +extern const CFAllocatorRef kCFAllocatorUseContext; +CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); +extern void CFRelease(CFStringRef cf); + +void DellocWithCFStringCreate1(CFAllocatorRef alloc) { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *bytes; + char * x; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); + if (st == noErr) { + CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}} + CFRelease(userStr); + } +} + +void DellocWithCFStringCreate2(CFAllocatorRef alloc) { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *bytes; + char * x; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); + if (st == noErr) { + CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}} + CFRelease(userStr); + } +} + +void DellocWithCFStringCreate3(CFAllocatorRef alloc) { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *bytes; + char * x; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); + if (st == noErr) { + CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext); + CFRelease(userStr); + } +} + +void DellocWithCFStringCreate4(CFAllocatorRef alloc) { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *bytes; + char * x; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); + if (st == noErr) { + CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}} + CFRelease(userStr); + } +} + +void radar10508828() { + UInt32 pwdLen = 0; + void* pwdBytes = 0; + OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); +#pragma unused(rc) + if (pwdBytes) + SecKeychainItemFreeContent(0, pwdBytes); +} + +void radar10508828_2() { + UInt32 pwdLen = 0; + void* pwdBytes = 0; + OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); + SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned.}} +} + +//Example from bug 10797. +__inline__ static +const char *__WBASLLevelString(int level) { + return "foo"; +} + +static int *bug10798(int *p, int columns, int prevRow) { + int *row = 0; + row = p + prevRow * columns; + prevRow += 2; + do { + ++prevRow; + row+=columns; + } while(10 >= row[1]); + return row; +} + +// Test inter-procedural behaviour. + +void my_FreeParam(void *attrList, void* X) { + SecKeychainItemFreeContent(attrList, X); +} + +void *my_AllocateReturn(OSStatus *st) { + unsigned int *ptr = 0; + UInt32 length; + void *outData; + *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + return outData; +} + +OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { + OSStatus err; + SecKeychainItemRef item; + err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", + passwordLength, password, &item); + return err; +} + +void allocAndFree1() { + unsigned int *ptr = 0; + OSStatus st = 0; + UInt32 length; + void *outData; + st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); + if (st == noErr) + my_FreeParam(ptr, outData); +} + +void consumeChar(char); + +void allocNoFree2(int x) { + OSStatus st = 0; + void *outData = my_AllocateReturn(&st); + if (x) { + consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} + return; + } else { + consumeChar(*(char*)outData); + } + return; +} + +void allocAndFree2(void *attrList) { + OSStatus st = 0; + void *outData = my_AllocateReturn(&st); + if (st == noErr) + my_FreeParam(attrList, outData); +} + +void allocNoFree3() { + UInt32 length = 32; + void *outData; + void *outData2; + OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} + st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} +} + +void allocAndFree3(void *attrList) { + UInt32 length = 32; + void *outData; + OSStatus st = my_Allocate_Param(&outData, &length); + if (st == noErr) + SecKeychainItemFreeContent(attrList, outData); +} + diff --git a/clang/test/Analysis/lambdas.cpp b/clang/test/Analysis/lambdas.cpp new file mode 100644 index 0000000..77b36c4 --- /dev/null +++ b/clang/test/Analysis/lambdas.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +struct X { X(const X&); }; +void f(X x) { (void) [x]{}; } + +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: x +// CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X) +// CHECK: 3: [B1.2] (CXXConstructExpr, struct X) +// CHECK: 4: [=x] { +// CHECK: } +// CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 + diff --git a/clang/test/Analysis/lvalue.cpp b/clang/test/Analysis/lvalue.cpp new file mode 100644 index 0000000..0cc42f5 --- /dev/null +++ b/clang/test/Analysis/lvalue.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s + +int f1() { + int x = 0, y = 1; + return x += y; // Should bind a location to 'x += y'. No crash. +} diff --git a/clang/test/Analysis/malloc-annotations.c b/clang/test/Analysis/malloc-annotations.c new file mode 100644 index 0000000..a0c1452 --- /dev/null +++ b/clang/test/Analysis/malloc-annotations.c @@ -0,0 +1,271 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,experimental.unix.MallocWithAnnotations -analyzer-store=region -verify %s +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); +void *calloc(size_t nmemb, size_t size); +void __attribute((ownership_returns(malloc))) *my_malloc(size_t); +void __attribute((ownership_takes(malloc, 1))) my_free(void *); +void my_freeBoth(void *, void *) + __attribute((ownership_holds(malloc, 1, 2))); +void __attribute((ownership_returns(malloc, 1))) *my_malloc2(size_t); +void __attribute((ownership_holds(malloc, 1))) my_hold(void *); + +// Duplicate attributes are silly, but not an error. +// Duplicate attribute has no extra effect. +// If two are of different kinds, that is an error and reported as such. +void __attribute((ownership_holds(malloc, 1))) +__attribute((ownership_holds(malloc, 1))) +__attribute((ownership_holds(malloc, 3))) my_hold2(void *, void *, void *); +void *my_malloc3(size_t); +void *myglobalpointer; +struct stuff { + void *somefield; +}; +struct stuff myglobalstuff; + +void f1() { + int *p = malloc(12); + return; // expected-warning{{Memory is never released; potential leak}} +} + +void f2() { + int *p = malloc(12); + free(p); + free(p); // expected-warning{{Attempt to free released memory}} +} + +void f2_realloc_0() { + int *p = malloc(12); + realloc(p,0); + realloc(p,0); // expected-warning{{Attempt to free released memory}} +} + +void f2_realloc_1() { + int *p = malloc(12); + int *q = realloc(p,0); // no-warning +} + +// ownership attributes tests +void naf1() { + int *p = my_malloc3(12); + return; // no-warning +} + +void n2af1() { + int *p = my_malloc2(12); + return; // expected-warning{{Memory is never released; potential leak}} +} + +void af1() { + int *p = my_malloc(12); + return; // expected-warning{{Memory is never released; potential leak}} +} + +void af1_b() { + int *p = my_malloc(12); // expected-warning{{Memory is never released; potential leak}} +} + +void af1_c() { + myglobalpointer = my_malloc(12); // no-warning +} + +// TODO: We will be able to handle this after we add support for tracking allocations stored in struct fields. +void af1_d() { + struct stuff mystuff; + mystuff.somefield = my_malloc(12); // false negative +} + +// Test that we can pass out allocated memory via pointer-to-pointer. +void af1_e(void **pp) { + *pp = my_malloc(42); // no-warning +} + +void af1_f(struct stuff *somestuff) { + somestuff->somefield = my_malloc(12); // no-warning +} + +// Allocating memory for a field via multiple indirections to our arguments is OK. +void af1_g(struct stuff **pps) { + *pps = my_malloc(sizeof(struct stuff)); // no-warning + (*pps)->somefield = my_malloc(42); // no-warning +} + +void af2() { + int *p = my_malloc(12); + my_free(p); + free(p); // expected-warning{{Attempt to free released memory}} +} + +void af2b() { + int *p = my_malloc(12); + free(p); + my_free(p); // expected-warning{{Attempt to free released memory}} +} + +void af2c() { + int *p = my_malloc(12); + free(p); + my_hold(p); // expected-warning{{Attempt to free released memory}} +} + +void af2d() { + int *p = my_malloc(12); + free(p); + my_hold2(0, 0, p); // expected-warning{{Attempt to free released memory}} +} + +// No leak if malloc returns null. +void af2e() { + int *p = my_malloc(12); + if (!p) + return; // no-warning + free(p); // no-warning +} + +// This case would inflict a double-free elsewhere. +// However, this case is considered an analyzer bug since it causes false-positives. +void af3() { + int *p = my_malloc(12); + my_hold(p); + free(p); // no-warning +} + +int * af4() { + int *p = my_malloc(12); + my_free(p); + return p; // expected-warning{{Use of memory after it is freed}} +} + +// This case is (possibly) ok, be conservative +int * af5() { + int *p = my_malloc(12); + my_hold(p); + return p; // no-warning +} + + + +// This case tests that storing malloc'ed memory to a static variable which is +// then returned is not leaked. In the absence of known contracts for functions +// or inter-procedural analysis, this is a conservative answer. +int *f3() { + static int *p = 0; + p = malloc(12); + return p; // no-warning +} + +// This case tests that storing malloc'ed memory to a static global variable +// which is then returned is not leaked. In the absence of known contracts for +// functions or inter-procedural analysis, this is a conservative answer. +static int *p_f4 = 0; +int *f4() { + p_f4 = malloc(12); + return p_f4; // no-warning +} + +int *f5() { + int *q = malloc(12); + q = realloc(q, 20); + return q; // no-warning +} + +void f6() { + int *p = malloc(12); + if (!p) + return; // no-warning + else + free(p); +} + +void f6_realloc() { + int *p = malloc(12); + if (!p) + return; // no-warning + else + realloc(p,0); +} + + +char *doit2(); +void pr6069() { + char *buf = doit2(); + free(buf); +} + +void pr6293() { + free(0); +} + +void f7() { + char *x = (char*) malloc(4); + free(x); + x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} +} + +void f7_realloc() { + char *x = (char*) malloc(4); + realloc(x,0); + x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} +} + +void PR6123() { + int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} +} + +void PR7217() { + int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} + buf[1] = 'c'; // not crash +} + +void mallocCastToVoid() { + void *p = malloc(2); + const void *cp = p; // not crash + free(p); +} + +void mallocCastToFP() { + void *p = malloc(2); + void (*fp)() = p; // not crash + free(p); +} + +// This tests that malloc() buffers are undefined by default +char mallocGarbage () { + char *buf = malloc(2); + char result = buf[1]; // expected-warning{{undefined}} + free(buf); + return result; +} + +// This tests that calloc() buffers need to be freed +void callocNoFree () { + char *buf = calloc(2,2); + return; // expected-warning{{never released}} +} + +// These test that calloc() buffers are zeroed by default +char callocZeroesGood () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] == 0) { + free(buf); + } + return result; // no-warning +} + +char callocZeroesBad () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] != 0) { + free(buf); // expected-warning{{never executed}} + } + return result; // expected-warning{{never released}} +} + +void testMultipleFreeAnnotations() { + int *p = malloc(12); + int *q = malloc(12); + my_freeBoth(p, q); +} + diff --git a/clang/test/Analysis/malloc-interprocedural.c b/clang/test/Analysis/malloc-interprocedural.c new file mode 100644 index 0000000..589bc4f --- /dev/null +++ b/clang/test/Analysis/malloc-interprocedural.c @@ -0,0 +1,98 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-ipa=inlining -analyzer-inline-max-stack-depth=5 -analyzer-inline-max-function-size=6 -analyzer-store=region -verify %s + +#include "system-header-simulator.h" + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void *valloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); +void *reallocf(void *ptr, size_t size); +void *calloc(size_t nmemb, size_t size); +extern void exit(int) __attribute__ ((__noreturn__)); + +static void my_malloc1(void **d, size_t size) { + *d = malloc(size); +} + +static void *my_malloc2(int elevel, size_t size) { + void *data; + data = malloc(size); + if (data == 0) + exit(0); + return data; +} + +static void my_free1(void *p) { + free(p); +} + +static void test1() { + void *data = 0; + my_malloc1(&data, 4); // expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}} +} + +static void test11() { + void *data = 0; + my_malloc1(&data, 4); + my_free1(data); +} + +static void testUniqueingByallocationSiteInTopLevelFunction() { + void *data = my_malloc2(1, 4); + data = 0; + int x = 5;// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}} + data = my_malloc2(1, 4);// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}} +} + +static void test3() { + void *data = my_malloc2(1, 4); + free(data); + data = my_malloc2(1, 4); + free(data); +} + +int test4() { + int *data = (int*)my_malloc2(1, 4); + my_free1(data); + data = (int *)my_malloc2(1, 4); + my_free1(data); + return *data; // expected-warning {{Use of memory after it is freed}} +} + +void test6() { + int *data = (int *)my_malloc2(1, 4); + my_free1((int*)data); + my_free1((int*)data); // expected-warning{{Use of memory after it is freed}} +} + +// TODO: We should warn here. +void test5() { + int *data; + my_free1((int*)data); +} + +static char *reshape(char *in) { + return 0; +} + +void testThatRemoveDeadBindingsRunBeforeEachCall() { + char *v = malloc(12); + v = reshape(v); + v = reshape(v);// expected-warning {{Memory is never released; potential leak of memory pointed to by 'v'}} +} + +// Test that we keep processing after 'return;' +void fooWithEmptyReturn(int x) { + if (x) + return; + x++; + return; +} + +int uafAndCallsFooWithEmptyReturn() { + int *x = (int*)malloc(12); + free(x); + fooWithEmptyReturn(12); + return *x; // expected-warning {{Use of memory after it is freed}} +} diff --git a/clang/test/Analysis/malloc-overflow.c b/clang/test/Analysis/malloc-overflow.c new file mode 100644 index 0000000..714fd3d --- /dev/null +++ b/clang/test/Analysis/malloc-overflow.c @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s + +#define NULL ((void *) 0) +typedef __typeof__(sizeof(int)) size_t; +extern void * malloc(size_t); + +void * f1(int n) +{ + return malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} +} + +void * f2(int n) +{ + return malloc(sizeof(int) * n); // // expected-warning {{the computation of the size of the memory allocation may overflow}} +} + +void * f3() +{ + return malloc(4 * sizeof(int)); // no-warning +} + +struct s4 +{ + int n; +}; + +void * f4(struct s4 *s) +{ + return malloc(s->n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} +} + +void * f5(struct s4 *s) +{ + struct s4 s2 = *s; + return malloc(s2.n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} +} + +void * f6(int n) +{ + return malloc((n + 1) * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} +} + +extern void * malloc (size_t); + +void * f7(int n) +{ + if (n > 10) + return NULL; + return malloc(n * sizeof(int)); // no-warning +} + +void * f8(int n) +{ + if (n < 10) + return malloc(n * sizeof(int)); // no-warning + else + return NULL; +} + +void * f9(int n) +{ + int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} + for (int i = 0; i < n; i++) + x[i] = i; + return x; +} + +void * f10(int n) +{ + int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} + int i = 0; + while (i < n) + x[i++] = 0; + return x; +} + +void * f11(int n) +{ + int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} + int i = 0; + do { + x[i++] = 0; + } while (i < n); + return x; +} + +void * f12(int n) +{ + n = (n > 10 ? 10 : n); + int * x = malloc(n * sizeof(int)); // no-warning + for (int i = 0; i < n; i++) + x[i] = i; + return x; +} + +struct s13 +{ + int n; +}; + +void * f13(struct s13 *s) +{ + if (s->n > 10) + return NULL; + return malloc(s->n * sizeof(int)); // no warning +} + +void * f14(int n) +{ + if (n < 0) + return NULL; + return malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}} +} diff --git a/clang/test/Analysis/malloc-overflow.cpp b/clang/test/Analysis/malloc-overflow.cpp new file mode 100644 index 0000000..c1ac6be --- /dev/null +++ b/clang/test/Analysis/malloc-overflow.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s + +class A { +public: + A& operator<<(const A &a); +}; + +void f() { + A a = A(), b = A(); + a << b; +} diff --git a/clang/test/Analysis/malloc-plist.c b/clang/test/Analysis/malloc-plist.c new file mode 100644 index 0000000..db2e0f0 --- /dev/null +++ b/clang/test/Analysis/malloc-plist.c @@ -0,0 +1,2814 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o %t %s +// RUN: FileCheck --input-file %t %s + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); + +void diagnosticTest(int in) { + if (in > 5) { + int *p = malloc(12); + (*p)++; + } + in++; // expected-warning {{leak}} +} + +void myArrayAllocation() { + int **A; + A = malloc(2*sizeof(int*)); + A[0] = 0;// expected-warning {{leak}} +} + +void reallocDiagnostics() { + char * buf = malloc(100); + char * tmp; + tmp = (char*)realloc(buf, 0x1000000); + if (!tmp) { + return;// expected-warning {{leak}} + } + buf = tmp; + free(buf); +} + +void *wrapper() { + void *x = malloc(100); + // This is intentionally done to test diagnostic emission. + if (x) + return x; + return 0; +} + +void test_wrapper() { + void *buf = wrapper(); + (void) buf; +} + +// Test what happens when the same call frees and allocated memory. +// Also tests the stack hint for parameters, when they are passed directly or via pointer. +void my_free(void *x) { + free(x); +} +void my_malloc_and_free(void **x) { + *x = malloc(100); + if (*x) + my_free(*x); + return; +} +void *test_double_action_call() { + void *buf; + my_malloc_and_free(&buf); + return buf; +} + +// Test stack hint for 'reallocation failed'. +char *my_realloc(char *buf) { + char *tmp; + tmp = (char*)realloc(buf, 0x1000000); + if (!tmp) { + return tmp; + } + return tmp; +} +void reallocIntra() { + char *buf = (char *)malloc(100); + buf = my_realloc(buf); + free(buf); +} + +// Test stack hint when returning a result. +static char *malloc_wrapper_ret() { + return (char*)malloc(12); +} +void use_ret() { + char *v; + v = malloc_wrapper_ret(); +} + +// Test that we refer to the last symbol used in the leak diagnostic. +void LeakedSymbol(int in) { + int *m = 0; + int *p; + p = (int*)malloc(12); + (*p)++; + m = p; + p = 0; + (*m)++; + in++; +} + +// CHECK: <?xml version="1.0" encoding="UTF-8"?> +// CHECK: <plist version="1.0"> +// CHECK: <dict> +// CHECK: <key>files</key> +// CHECK: <array> +// CHECK: </array> +// CHECK: <key>diagnostics</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>27</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>27</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>11</integer> +// CHECK: <key>col</key><integer>27</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'p'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'p'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'p'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>diagnosticTest</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>14</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>18</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>18</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>30</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>30</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>30</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>21</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>21</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>21</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'A'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'A'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'A'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>myArrayAllocation</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>21</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Attempt to reallocate memory</string> +// CHECK: <key>message</key> +// CHECK: <string>Attempt to reallocate memory</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>26</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'tmp' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'tmp' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Reallocation failed</string> +// CHECK: <key>message</key> +// CHECK: <string>Reallocation failed</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>27</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>reallocDiagnostics</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'wrapper'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'wrapper'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>34</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'test_wrapper'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'test_wrapper'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>34</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>34</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>35</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'x' is non-null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'x' is non-null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returned allocated memory</string> +// CHECK: <key>message</key> +// CHECK: <string>Returned allocated memory</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>43</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>45</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>45</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>45</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_wrapper</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>45</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'my_malloc_and_free'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'my_malloc_and_free'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>52</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'test_double_action_call'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'test_double_action_call'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>52</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>52</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>20</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>20</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>20</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>17</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'my_free'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'my_free'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>49</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>2</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'my_malloc_and_free'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'my_malloc_and_free'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>49</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>49</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>2</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is released</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is released</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>17</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>2</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returned released memory via 1st parameter</string> +// CHECK: <key>message</key> +// CHECK: <string>Returned released memory via 1st parameter</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>17</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>56</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>56</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returned released memory via 1st parameter</string> +// CHECK: <key>message</key> +// CHECK: <string>Returned released memory via 1st parameter</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>60</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>14</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Use of memory after it is freed</string> +// CHECK: <key>message</key> +// CHECK: <string>Use of memory after it is freed</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Use of memory after it is freed</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Use-after-free</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_double_action_call</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>61</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>35</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>35</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>74</integer> +// CHECK: <key>col</key><integer>35</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'my_realloc'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'my_realloc'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>65</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'reallocIntra'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'reallocIntra'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>65</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>65</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>66</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>66</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>66</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>66</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Attempt to reallocate memory</string> +// CHECK: <key>message</key> +// CHECK: <string>Attempt to reallocate memory</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>18</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>67</integer> +// CHECK: <key>col</key><integer>40</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'tmp' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'tmp' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>12</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Reallocation failed</string> +// CHECK: <key>message</key> +// CHECK: <string>Reallocation failed</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>68</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>69</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>69</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Reallocation of 1st parameter failed</string> +// CHECK: <key>message</key> +// CHECK: <string>Reallocation of 1st parameter failed</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>75</integer> +// CHECK: <key>col</key><integer>25</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>13</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>reallocIntra</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>84</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Calling 'malloc_wrapper_ret'</string> +// CHECK: <key>message</key> +// CHECK: <string>Calling 'malloc_wrapper_ret'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>80</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Entered call from 'use_ret'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call from 'use_ret'</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>80</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>80</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>19</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>19</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>19</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>81</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>1</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Returned allocated memory</string> +// CHECK: <key>message</key> +// CHECK: <string>Returned allocated memory</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>9</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>85</integer> +// CHECK: <key>col</key><integer>28</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'v'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'v'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'v'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>use_ret</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>86</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>90</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>90</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>24</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>24</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is allocated</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>15</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>92</integer> +// CHECK: <key>col</key><integer>24</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'm'</string> +// CHECK: <key>message</key> +// CHECK: <string>Memory is never released; potential leak of memory pointed to by 'm'</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'm'</string> +// CHECK: <key>category</key><string>Memory Error</string> +// CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>LeakedSymbol</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>97</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </plist> + diff --git a/clang/test/Analysis/malloc-sizeof.c b/clang/test/Analysis/malloc-sizeof.c new file mode 100644 index 0000000..d2b3bcf --- /dev/null +++ b/clang/test/Analysis/malloc-sizeof.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.MallocSizeof -verify %s + +#include <stddef.h> + +void *malloc(size_t size); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); + +struct A {}; +struct B {}; + +void foo() { + int *ip1 = malloc(sizeof(1)); + int *ip2 = malloc(4 * sizeof(int)); + + long *lp1 = malloc(sizeof(short)); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'short'}} + long *lp2 = malloc(5 * sizeof(double)); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'double'}} + long *lp3 = malloc(5 * sizeof(char) + 2); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'char'}} + + struct A *ap1 = calloc(1, sizeof(struct A)); + struct A *ap2 = calloc(2, sizeof(*ap1)); + struct A *ap3 = calloc(2, sizeof(ap1)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct A *'}} + struct A *ap4 = calloc(3, sizeof(struct A*)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct A *'}} + struct A *ap5 = calloc(4, sizeof(struct B)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct B'}} + struct A *ap6 = realloc(ap5, sizeof(struct A)); + struct A *ap7 = realloc(ap5, sizeof(struct B)); // expected-warning {{Result of 'realloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct B'}} +} diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c new file mode 100644 index 0000000..3b47123 --- /dev/null +++ b/clang/test/Analysis/malloc.c @@ -0,0 +1,809 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc -analyzer-store=region -verify %s +#include "system-header-simulator.h" + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void *valloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); +void *reallocf(void *ptr, size_t size); +void *calloc(size_t nmemb, size_t size); + +void myfoo(int *p); +void myfooint(int p); +char *fooRetPtr(); + +void f1() { + int *p = malloc(12); + return; // expected-warning{{Memory is never released; potential leak}} +} + +void f2() { + int *p = malloc(12); + free(p); + free(p); // expected-warning{{Attempt to free released memory}} +} + +void f2_realloc_0() { + int *p = malloc(12); + realloc(p,0); + realloc(p,0); // expected-warning{{Attempt to free released memory}} +} + +void f2_realloc_1() { + int *p = malloc(12); + int *q = realloc(p,0); // no-warning +} + +void reallocNotNullPtr(unsigned sizeIn) { + unsigned size = 12; + char *p = (char*)malloc(size); + if (p) { + char *q = (char*)realloc(p, sizeIn); + char x = *q; // expected-warning {{Memory is never released; potential leak}} + } +} + +int *realloctest1() { + int *q = malloc(12); + q = realloc(q, 20); + return q; // no warning - returning the allocated value +} + +// p should be freed if realloc fails. +void reallocFails() { + char *p = malloc(12); + char *r = realloc(p, 12+1); + if (!r) { + free(p); + } else { + free(r); + } +} + +void reallocSizeZero1() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); + } else { + free(r); + } +} + +void reallocSizeZero2() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); + } else { + free(r); + } + free(p); // expected-warning {{Attempt to free released memory}} +} + +void reallocSizeZero3() { + char *p = malloc(12); + char *r = realloc(p, 0); + free(r); +} + +void reallocSizeZero4() { + char *r = realloc(0, 0); + free(r); +} + +void reallocSizeZero5() { + char *r = realloc(0, 0); +} + +void reallocPtrZero1() { + char *r = realloc(0, 12); // expected-warning {{Memory is never released; potential leak}} +} + +void reallocPtrZero2() { + char *r = realloc(0, 12); + if (r) + free(r); +} + +void reallocPtrZero3() { + char *r = realloc(0, 12); + free(r); +} + +void reallocRadar6337483_1() { + char *buf = malloc(100); + buf = (char*)realloc(buf, 0x1000000); + if (!buf) { + return;// expected-warning {{Memory is never released; potential leak}} + } + free(buf); +} + +void reallocRadar6337483_2() { + char *buf = malloc(100); + char *buf2 = (char*)realloc(buf, 0x1000000); + if (!buf2) { // expected-warning {{Memory is never released; potential leak}} + ; + } else { + free(buf2); + } +} + +void reallocRadar6337483_3() { + char * buf = malloc(100); + char * tmp; + tmp = (char*)realloc(buf, 0x1000000); + if (!tmp) { + free(buf); + return; + } + buf = tmp; + free(buf); +} + +void reallocRadar6337483_4() { + char *buf = malloc(100); + char *buf2 = (char*)realloc(buf, 0x1000000); + if (!buf2) { + return; // expected-warning {{Memory is never released; potential leak}} + } else { + free(buf2); + } +} + +int *reallocfTest1() { + int *q = malloc(12); + q = reallocf(q, 20); + return q; // no warning - returning the allocated value +} + +void reallocfRadar6337483_4() { + char *buf = malloc(100); + char *buf2 = (char*)reallocf(buf, 0x1000000); + if (!buf2) { + return; // no warning - reallocf frees even on failure + } else { + free(buf2); + } +} + +void reallocfRadar6337483_3() { + char * buf = malloc(100); + char * tmp; + tmp = (char*)reallocf(buf, 0x1000000); + if (!tmp) { + free(buf); // expected-warning {{Attempt to free released memory}} + return; + } + buf = tmp; + free(buf); +} + +void reallocfPtrZero1() { + char *r = reallocf(0, 12); // expected-warning {{Memory is never released; potential leak}} +} + + +// This case tests that storing malloc'ed memory to a static variable which is +// then returned is not leaked. In the absence of known contracts for functions +// or inter-procedural analysis, this is a conservative answer. +int *f3() { + static int *p = 0; + p = malloc(12); + return p; // no-warning +} + +// This case tests that storing malloc'ed memory to a static global variable +// which is then returned is not leaked. In the absence of known contracts for +// functions or inter-procedural analysis, this is a conservative answer. +static int *p_f4 = 0; +int *f4() { + p_f4 = malloc(12); + return p_f4; // no-warning +} + +int *f5() { + int *q = malloc(12); + q = realloc(q, 20); + return q; // no-warning +} + +void f6() { + int *p = malloc(12); + if (!p) + return; // no-warning + else + free(p); +} + +void f6_realloc() { + int *p = malloc(12); + if (!p) + return; // no-warning + else + realloc(p,0); +} + + +char *doit2(); +void pr6069() { + char *buf = doit2(); + free(buf); +} + +void pr6293() { + free(0); +} + +void f7() { + char *x = (char*) malloc(4); + free(x); + x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} +} + +void f7_realloc() { + char *x = (char*) malloc(4); + realloc(x,0); + x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} +} + +void PR6123() { + int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} +} + +void PR7217() { + int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} + buf[1] = 'c'; // not crash +} + +void mallocCastToVoid() { + void *p = malloc(2); + const void *cp = p; // not crash + free(p); +} + +void mallocCastToFP() { + void *p = malloc(2); + void (*fp)() = p; // not crash + free(p); +} + +// This tests that malloc() buffers are undefined by default +char mallocGarbage () { + char *buf = malloc(2); + char result = buf[1]; // expected-warning{{undefined}} + free(buf); + return result; +} + +// This tests that calloc() buffers need to be freed +void callocNoFree () { + char *buf = calloc(2,2); + return; // expected-warning{{never released}} +} + +// These test that calloc() buffers are zeroed by default +char callocZeroesGood () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] == 0) { + free(buf); + } + return result; // no-warning +} + +char callocZeroesBad () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] != 0) { + free(buf); // expected-warning{{never executed}} + } + return result; // expected-warning{{never released}} +} + +void nullFree() { + int *p = 0; + free(p); // no warning - a nop +} + +void paramFree(int *p) { + myfoo(p); + free(p); // no warning + myfoo(p); // TODO: This should be a warning. +} + +int* mallocEscapeRet() { + int *p = malloc(12); + return p; // no warning +} + +void mallocEscapeFoo() { + int *p = malloc(12); + myfoo(p); + return; // no warning +} + +void mallocEscapeFree() { + int *p = malloc(12); + myfoo(p); + free(p); +} + +void mallocEscapeFreeFree() { + int *p = malloc(12); + myfoo(p); + free(p); + free(p); // expected-warning{{Attempt to free released memory}} +} + +void mallocEscapeFreeUse() { + int *p = malloc(12); + myfoo(p); + free(p); + myfoo(p); // expected-warning{{Use of memory after it is freed}} +} + +int *myalloc(); +void myalloc2(int **p); + +void mallocEscapeFreeCustomAlloc() { + int *p = malloc(12); + myfoo(p); + free(p); + p = myalloc(); + free(p); // no warning +} + +void mallocEscapeFreeCustomAlloc2() { + int *p = malloc(12); + myfoo(p); + free(p); + myalloc2(&p); + free(p); // no warning +} + +void mallocBindFreeUse() { + int *x = malloc(12); + int *y = x; + free(y); + myfoo(x); // expected-warning{{Use of memory after it is freed}} +} + +void mallocEscapeMalloc() { + int *p = malloc(12); + myfoo(p); + p = malloc(12); // expected-warning{{Memory is never released; potential leak}} +} + +void mallocMalloc() { + int *p = malloc(12); + p = malloc(12); // expected-warning 2 {{Memory is never released; potential leak}} +} + +void mallocFreeMalloc() { + int *p = malloc(12); + free(p); + p = malloc(12); + free(p); +} + +void mallocFreeUse_params() { + int *p = malloc(12); + free(p); + myfoo(p); //expected-warning{{Use of memory after it is freed}} +} + +void mallocFreeUse_params2() { + int *p = malloc(12); + free(p); + myfooint(*p); //expected-warning{{Use of memory after it is freed}} +} + +void mallocFailedOrNot() { + int *p = malloc(12); + if (!p) + free(p); + else + free(p); +} + +struct StructWithInt { + int g; +}; + +int *mallocReturnFreed() { + int *p = malloc(12); + free(p); + return p; // expected-warning {{Use of memory after it is freed}} +} + +int useAfterFreeStruct() { + struct StructWithInt *px= malloc(sizeof(struct StructWithInt)); + px->g = 5; + free(px); + return px->g; // expected-warning {{Use of memory after it is freed}} +} + +void nonSymbolAsFirstArg(int *pp, struct StructWithInt *p); + +void mallocEscapeFooNonSymbolArg() { + struct StructWithInt *p = malloc(sizeof(struct StructWithInt)); + nonSymbolAsFirstArg(&p->g, p); + return; // no warning +} + +void mallocFailedOrNotLeak() { + int *p = malloc(12); + if (p == 0) + return; // no warning + else + return; // expected-warning {{Memory is never released; potential leak}} +} + +void mallocAssignment() { + char *p = malloc(12); + p = fooRetPtr(); // expected-warning {{leak}} +} + +int vallocTest() { + char *mem = valloc(12); + return 0; // expected-warning {{Memory is never released; potential leak}} +} + +void vallocEscapeFreeUse() { + int *p = valloc(12); + myfoo(p); + free(p); + myfoo(p); // expected-warning{{Use of memory after it is freed}} +} + +int *Gl; +struct GlStTy { + int *x; +}; + +struct GlStTy GlS = {0}; + +void GlobalFree() { + free(Gl); +} + +void GlobalMalloc() { + Gl = malloc(12); +} + +void GlobalStructMalloc() { + int *a = malloc(12); + GlS.x = a; +} + +void GlobalStructMallocFree() { + int *a = malloc(12); + GlS.x = a; + free(GlS.x); +} + +char *ArrayG[12]; + +void globalArrayTest() { + char *p = (char*)malloc(12); + ArrayG[0] = p; +} + +// Make sure that we properly handle a pointer stored into a local struct/array. +typedef struct _StructWithPtr { + int *memP; +} StructWithPtr; + +static StructWithPtr arrOfStructs[10]; + +void testMalloc() { + int *x = malloc(12); + StructWithPtr St; + St.memP = x; + arrOfStructs[0] = St; +} + +StructWithPtr testMalloc2() { + int *x = malloc(12); + StructWithPtr St; + St.memP = x; + return St; +} + +int *testMalloc3() { + int *x = malloc(12); + int *y = x; + return y; +} + +void testElemRegion1() { + char *x = (void*)malloc(2); + int *ix = (int*)x; + free(&(x[0])); +} + +void testElemRegion2(int **pp) { + int *p = malloc(12); + *pp = p; + free(pp[0]); +} + +void testElemRegion3(int **pp) { + int *p = malloc(12); + *pp = p; + free(*pp); +} +// Region escape testing. + +unsigned takePtrToPtr(int **p); +void PassTheAddrOfAllocatedData(int f) { + int *p = malloc(12); + // We don't know what happens after the call. Should stop tracking here. + if (takePtrToPtr(&p)) + f++; + free(p); // no warning +} + +struct X { + int *p; +}; +unsigned takePtrToStruct(struct X *s); +int ** foo2(int *g, int f) { + int *p = malloc(12); + struct X *px= malloc(sizeof(struct X)); + px->p = p; + // We don't know what happens after this call. Should not track px nor p. + if (takePtrToStruct(px)) + f++; + free(p); + return 0; +} + +struct X* RegInvalidationDetect1(struct X *s2) { + struct X *px= malloc(sizeof(struct X)); + px->p = 0; + px = s2; + return px; // expected-warning {{Memory is never released; potential leak}} +} + +struct X* RegInvalidationGiveUp1() { + int *p = malloc(12); + struct X *px= malloc(sizeof(struct X)); + px->p = p; + return px; +} + +int **RegInvalidationDetect2(int **pp) { + int *p = malloc(12); + pp = &p; + pp++; + return 0;// expected-warning {{Memory is never released; potential leak}} +} + +extern void exit(int) __attribute__ ((__noreturn__)); +void mallocExit(int *g) { + struct xx *p = malloc(12); + if (g != 0) + exit(1); + free(p); + return; +} + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + __attribute__ ((__noreturn__)); +#define assert(expr) \ + ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) +void mallocAssert(int *g) { + struct xx *p = malloc(12); + + assert(g != 0); + free(p); + return; +} + +void doNotInvalidateWhenPassedToSystemCalls(char *s) { + char *p = malloc(12); + strlen(p); + strcpy(p, s); // expected-warning {{leak}} +} + +// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p. +void symbolLostWithStrcpy(char *s) { + char *p = malloc(12); + p = strcpy(p, s); + free(p); +} + + +// The same test as the one above, but with what is actually generated on a mac. +static __inline char * +__inline_strcpy_chk (char *restrict __dest, const char *restrict __src) +{ + return __builtin___strcpy_chk (__dest, __src, __builtin_object_size (__dest, 2 > 1)); +} + +void symbolLostWithStrcpy_InlineStrcpyVersion(char *s) { + char *p = malloc(12); + p = ((__builtin_object_size (p, 0) != (size_t) -1) ? __builtin___strcpy_chk (p, s, __builtin_object_size (p, 2 > 1)) : __inline_strcpy_chk (p, s)); + free(p); +} + +// Here we are returning a pointer one past the allocated value. An idiom which +// can be used for implementing special malloc. The correct uses of this might +// be rare enough so that we could keep this as a warning. +static void *specialMalloc(int n){ + int *p; + p = malloc( n+8 ); + if( p ){ + p[0] = n; + p++; + } + return p; +} + +// Potentially, the user could free the struct by performing pointer arithmetic on the return value. +// This is a variation of the specialMalloc issue, though probably would be more rare in correct code. +int *specialMallocWithStruct() { + struct StructWithInt *px= malloc(sizeof(struct StructWithInt)); + return &(px->g); +} + +// Test various allocation/deallocation functions. + +char *strdup(const char *s); +char *strndup(const char *s, size_t n); + +void testStrdup(const char *s, unsigned validIndex) { + char *s2 = strdup(s); + s2[validIndex + 1] = 'b';// expected-warning {{Memory is never released; potential leak}} +} + +int testStrndup(const char *s, unsigned validIndex, unsigned size) { + char *s2 = strndup(s, size); + s2 [validIndex + 1] = 'b'; + if (s2[validIndex] != 'a') + return 0; + else + return 1;// expected-warning {{Memory is never released; potential leak}} +} + +void testStrdupContentIsDefined(const char *s, unsigned validIndex) { + char *s2 = strdup(s); + char result = s2[1];// no warning + free(s2); +} + +// ---------------------------------------------------------------------------- +// Test the system library functions to which the pointer can escape. +// This tests false positive suppression. + +// For now, we assume memory passed to pthread_specific escapes. +// TODO: We could check that if a new pthread binding is set, the existing +// binding must be freed; otherwise, a memory leak can occur. +void testPthereadSpecificEscape(pthread_key_t key) { + void *buf = malloc(12); + pthread_setspecific(key, buf); // no warning +} + +// PR12101: Test funopen(). +static int releasePtr(void *_ctx) { + free(_ctx); + return 0; +} +FILE *useFunOpen() { + void *ctx = malloc(sizeof(int)); + FILE *f = funopen(ctx, 0, 0, 0, releasePtr); // no warning + if (f == 0) { + free(ctx); + } + return f; +} +FILE *useFunOpenNoReleaseFunction() { + void *ctx = malloc(sizeof(int)); + FILE *f = funopen(ctx, 0, 0, 0, 0); + if (f == 0) { + free(ctx); + } + return f; // expected-warning{{leak}} +} + +// Test setbuf, setvbuf. +int my_main_no_warning() { + char *p = malloc(100); + setvbuf(stdout, p, 0, 100); + return 0; +} +int my_main_no_warning2() { + char *p = malloc(100); + setbuf(__stdoutp, p); + return 0; +} +int my_main_warn(FILE *f) { + char *p = malloc(100); + setvbuf(f, p, 0, 100); + return 0;// expected-warning {{leak}} +} + +// <rdar://problem/10978247>. +// some people use stack allocated memory as an optimization to avoid +// a heap allocation for small work sizes. This tests the analyzer's +// understanding that the malloc'ed memory is not the same as stackBuffer. +void radar10978247(int myValueSize) { + char stackBuffer[128]; + char *buffer; + + if (myValueSize <= sizeof(stackBuffer)) + buffer = stackBuffer; + else + buffer = malloc(myValueSize); + + // do stuff with the buffer + if (buffer != stackBuffer) + free(buffer); +} + +void radar10978247_positive(int myValueSize) { + char stackBuffer[128]; + char *buffer; + + if (myValueSize <= sizeof(stackBuffer)) + buffer = stackBuffer; + else + buffer = malloc(myValueSize); + + // do stuff with the buffer + if (buffer == stackBuffer) // expected-warning {{leak}} + return; +} + +// ---------------------------------------------------------------------------- +// Below are the known false positives. + +// TODO: There should be no warning here. This one might be difficult to get rid of. +void dependsOnValueOfPtr(int *g, unsigned f) { + int *p; + + if (f) { + p = g; + } else { + p = malloc(12); + } + + if (p != g) + free(p); + else + return; // expected-warning{{Memory is never released; potential leak}} + return; +} + +// ---------------------------------------------------------------------------- +// False negatives. + +// TODO: This requires tracking symbols stored inside the structs/arrays. +void testMalloc5() { + StructWithPtr St; + StructWithPtr *pSt = &St; + pSt->memP = malloc(12); +} + +// TODO: This is another false negative. +void testMallocWithParam(int **p) { + *p = (int*) malloc(sizeof(int)); + *p = 0; +} + +void testMallocWithParam_2(int **p) { + *p = (int*) malloc(sizeof(int)); +} + +// TODO: This should produce a warning, similar to the previous issue. +void localArrayTest() { + char *p = (char*)malloc(12); + char *ArrayL[12]; + ArrayL[0] = p; +} + diff --git a/clang/test/Analysis/malloc.cpp b/clang/test/Analysis/malloc.cpp new file mode 100644 index 0000000..8f80b2b --- /dev/null +++ b/clang/test/Analysis/malloc.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc -analyzer-store=region -verify %s + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); +void *calloc(size_t nmemb, size_t size); + +// Test for radar://11110132. +struct Foo { + mutable void* m_data; + Foo(void* data) : m_data(data) {} +}; +Foo aFunction() { + return malloc(10); +} diff --git a/clang/test/Analysis/malloc.m b/clang/test/Analysis/malloc.m new file mode 100644 index 0000000..6c94118 --- /dev/null +++ b/clang/test/Analysis/malloc.m @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -Wno-objc-root-class %s +#include "system-header-simulator-objc.h" + +@class NSString; +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +// RDar10579586 - Test use of malloc() with Objective-C string literal as a +// test condition. Not really a malloc() issue, but this also exercises +// the check that malloc() returns uninitialized memory. +@interface RDar10579586 +struct rdar0579586_str { + char str_c; +}; +@end + +void rdar10579586(char x); + +@implementation RDar10579586 ++ (NSString *)foobar +{ + struct rdar0579586_str *buffer = ((void*)0); + NSString *error = ((void*)0); + + if ((buffer = malloc(sizeof(struct rdar0579586_str))) == ((void*)0)) + error = @"buffer allocation failure"; + + if (error != ((void*)0)) + return error; + + rdar10579586(buffer->str_c); // expected-warning {{Function call argument is an uninitialized value}} + free(buffer); + return ((void*)0); +} +@end + diff --git a/clang/test/Analysis/malloc.mm b/clang/test/Analysis/malloc.mm new file mode 100644 index 0000000..3515a4f --- /dev/null +++ b/clang/test/Analysis/malloc.mm @@ -0,0 +1,156 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s +#include "system-header-simulator-objc.h" + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +// Done with headers. Start testing. +void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength]; + free(data); // no warning +} + +void testNSDataFreeWhenDoneYES(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning +} + +void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning +} + + +void testNSStringFreeWhenDoneYES(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning +} + +void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) { + unichar *data = (unichar*)malloc(42); + NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning +} + + +void testNSDataFreeWhenDoneNO(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} +} + +void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} +} + + +void testNSStringFreeWhenDoneNO(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}} +} + +void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) { + unichar *data = (unichar*)malloc(42); + NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}} +} + +// TODO: False Negative. +void testNSDatafFreeWhenDoneFN(NSUInteger dataLength) { + unsigned char *data = (unsigned char *)malloc(42); + NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; + free(data); // false negative +} + +// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided. +void testNSDatafFreeWhenDone(NSUInteger dataLength) { + CFStringRef str; + char *bytes = (char*)malloc(12); + str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning + CFRelease(str); // default allocator also frees bytes +} + +void stringWithExternalContentsExample(void) { +#define BufferSize 1000 + CFMutableStringRef mutStr; + UniChar *myBuffer; + + myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar)); + + mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}} + + CFRelease(mutStr); + //free(myBuffer); +} + +// PR12101 : pointers can escape through custom deallocators set on creation of a container. +void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) { + void *key = malloc(12); + void *val = malloc(12); + CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(x, key, val); + return;// no-warning +} + +NSData *radar10976702() { + void *bytes = malloc(10); + return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning +} + +void testBlocks() { + int *x= (int*)malloc(sizeof(int)); + int (^myBlock)(int) = ^(int num) { + free(x); + return num; + }; + myBlock(3); +} + +// Test NSMapInsert. +@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> +@end +extern void *NSMapGet(NSMapTable *table, const void *key); +extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); +extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); +char *strdup(const char *s); + +NSString * radar11152419(NSString *string1, NSMapTable *map) { + const char *strkey = "key"; + NSString *string = ( NSString *)NSMapGet(map, strkey); + if (!string) { + string = [string1 copy]; + NSMapInsert(map, strdup(strkey), (void*)string); // no warning + NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning + } + return string; +} + +// Test that we handle pointer escaping through OSAtomicEnqueue. +typedef volatile struct { + void *opaque1; + long opaque2; +} OSQueueHead; +void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import)); +static inline void radar11111210(OSQueueHead *pool) { + void *newItem = malloc(4); + OSAtomicEnqueue(pool, newItem, 4); +} + +// Pointer might escape through CGDataProviderCreateWithData (radar://11187558). +typedef struct CGDataProvider *CGDataProviderRef; +typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, + size_t size); +extern CGDataProviderRef CGDataProviderCreateWithData(void *info, + const void *data, size_t size, + CGDataProviderReleaseDataCallback releaseData) + __attribute__((visibility("default"))); +void *calloc(size_t, size_t); + +static void releaseDataCallback (void *info, const void *data, size_t size) { +#pragma unused (info, size) + free((void*)data); +} +void testCGDataProviderCreateWithData() { + void* b = calloc(8, 8); + CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback); +}
\ No newline at end of file diff --git a/clang/test/Analysis/method-arg-decay.m b/clang/test/Analysis/method-arg-decay.m new file mode 100644 index 0000000..a36d81e --- /dev/null +++ b/clang/test/Analysis/method-arg-decay.m @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -analyzer-checker=core -verify %s +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 <NSObject> { +} +@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray; +typedef struct { +} + NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString; +typedef struct _NSRange { +} + NSRange; +@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range; +- (id)objectAtIndex:(NSUInteger)index; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; +@end @class NSArray, NSDictionary, NSString, NSError; +@interface NSSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end extern NSString *NSAccessibilityRoleDescription(NSString *role, NSString *subrole) ; +@interface NSResponder : NSObject <NSCoding> { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@interface NSWindowController : NSResponder <NSCoding> { +} +@end @class NSArray, NSFont, NSTabViewItem; +@interface NSTabView : NSView { +} +- (NSArray *)tabViewItems; +- (NSString *)label; +@end typedef enum { +PBXNoItemChanged = 0x00, PBXProjectItemChanged = 0x01, PBXReferenceChanged = 0x02, PBXGroupChanged = 0x04, PBXTargetChanged = 0x08, PBXBuildPhaseChanged = 0x10, PBXBuildFileChanged = 0x20, PBXBreakpointChanged = 0x40, } + PBXArchiveMask; +@interface PBXModule : NSWindowController { +} +@end typedef enum { +PBXFindMatchContains, PBXFindMatchStartsWith, PBXFindMatchWholeWords, PBXFindMatchEndsWith } + PBXFindMatchStyle; +@protocol PBXSelectableText - (NSString *)selectedString; +@end @protocol PBXFindableText <PBXSelectableText> - (BOOL)findText:(NSString *)string ignoreCase:(BOOL)ignoreCase matchStyle:(PBXFindMatchStyle)matchStyle backwards:(BOOL)backwards wrap:(BOOL)wrap; +@end @class PBXProjectDocument, PBXProject, PBXAttributedStatusView; +@interface PBXProjectModule : PBXModule <PBXFindableText> { +} +@end @class PBXBookmark; +@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection; // expected-note {{method 'performAction:withSelection:' declared here}} +@end @class XCPropertyDictionary, XCPropertyCondition, XCPropertyConditionSet, XCMutablePropertyConditionSet; +extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExposedModulesOnly); +@interface NSString (StringUtilities) - (NSString *) trimToLength:(NSInteger)length preserveRange:(NSRange)range; +- (id) objectOfType:(Class)type matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data; +@end @class XCControlView; +@protocol XCDockViewHeader - (NSImage *) headerImage; +@end @class XCDockableTabModule; +@interface XCExtendedTabView : NSTabView <XCDockViewHeader> { +} +@end @class PBXProjectDocument, PBXFileReference, PBXModule, XCWindowTool; +@interface XCPerspectiveModule : PBXProjectModule <PBXSelectionTarget> { // expected-note {{required for direct or indirect protocol 'PBXSelectionTarget'}} + XCExtendedTabView *_perspectivesTabView; +} +- (PBXModule *) moduleForTab:(NSTabViewItem *)item; // expected-note {{method definition for 'moduleForTab:' not found}} +@end +@implementation XCPerspectiveModule // expected-warning {{incomplete implementation}} expected-warning {{method 'performAction:withSelection:' in protocol not implemented}}} ++ (void) openForProjectDocument:(PBXProjectDocument *)projectDocument { +} +- (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data { + NSArray *allItems = [_perspectivesTabView tabViewItems]; + NSInteger i, c = [allItems count]; + for (i = 0; + i < c; + i++) { + NSTabViewItem *item = [allItems objectAtIndex:i]; + if ([[item label] isEqual:perspectiveIdentifer]) { + PBXProjectModule *pModule = (PBXProjectModule *)[self moduleForTab:item]; + PBXModule *obj = [XCFindPossibleKeyModules(pModule, (BOOL)0) objectOfType:type matchingFunction:comparator usingData:data]; + } + } + return 0; +} +- (BOOL)buffer:(char *)buf containsAnyPrompts:(char *[])prompts +{ + prompts++; + return (BOOL)0; +} +@end diff --git a/clang/test/Analysis/method-call-intra-p.cpp b/clang/test/Analysis/method-call-intra-p.cpp new file mode 100644 index 0000000..701479f --- /dev/null +++ b/clang/test/Analysis/method-call-intra-p.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s + +// Intra-procedural C++ tests. + +// Test relaxing function call arguments invalidation to be aware of const +// arguments. radar://10595327 +struct InvalidateArgs { + void ttt(const int &nptr); + virtual void vttt(const int *nptr); +}; +struct ChildOfInvalidateArgs: public InvalidateArgs { + virtual void vttt(const int *nptr); +}; +void declarationFun(int x) { + InvalidateArgs t; + x = 3; + int y = x + 1; + int *p = 0; + t.ttt(y); + if (x == y) + y = *p; // no-warning +} +void virtualFun(int x) { + ChildOfInvalidateArgs t; + InvalidateArgs *pt = &t; + x = 3; + int y = x + 1; + int *p = 0; + pt->vttt(&y); + if (x == y) + y = *p; // no-warning +} diff --git a/clang/test/Analysis/method-call.cpp b/clang/test/Analysis/method-call.cpp new file mode 100644 index 0000000..323fffe --- /dev/null +++ b/clang/test/Analysis/method-call.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s +// XFAIL: * + +struct A { + int x; + A(int a) { x = a; } + int getx() const { return x; } +}; + +void f1() { + A x(3); + if (x.getx() == 3) { + int *p = 0; + *p = 3; // expected-warning{{Dereference of null pointer}} + } else { + int *p = 0; + *p = 3; // no-warning + } +} + +void f2() { + const A &x = A(3); + if (x.getx() == 3) { + int *p = 0; + *p = 3; // expected-warning{{Dereference of null pointer}} + } else { + int *p = 0; + *p = 3; // no-warning + } +} + +void f3() { + const A &x = (A)3; + if (x.getx() == 3) { + int *p = 0; + *p = 3; // expected-warning{{Dereference of null pointer}} + } else { + int *p = 0; + *p = 3; // no-warning + } +} diff --git a/clang/test/Analysis/misc-ps-64.m b/clang/test/Analysis/misc-ps-64.m new file mode 100644 index 0000000..e20a27f --- /dev/null +++ b/clang/test/Analysis/misc-ps-64.m @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s + +// <rdar://problem/6440393> - 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); +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); +} + +// <rdar://problem/6845148> - 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/clang/test/Analysis/misc-ps-cxx0x.cpp b/clang/test/Analysis/misc-ps-cxx0x.cpp new file mode 100644 index 0000000..b4dee31 --- /dev/null +++ b/clang/test/Analysis/misc-ps-cxx0x.cpp @@ -0,0 +1,75 @@ +// RUN: %clang --analyze -std=c++11 %s -Xclang -verify -o /dev/null + +void test_static_assert() { + static_assert(sizeof(void *) == sizeof(void*), "test_static_assert"); +} + +void test_analyzer_working() { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} +} + +// Test that pointer-to-member functions don't cause the analyzer +// to crash. +struct RDar10243398 { + void bar(int x); +}; + +typedef void (RDar10243398::*RDar10243398MemberFn)(int x); + +void test_rdar10243398(RDar10243398 *p) { + RDar10243398MemberFn q = &RDar10243398::bar; + ((*p).*(q))(1); +} + +// Tests for CXXTemporaryObjectExpr. +struct X { + X( int *ip, int ); +}; + +// Test to see if CXXTemporaryObjectExpr is being handled. +int tempobj1() +{ + int j; + int i; + X a = X( &j, 1 ); + + return i; // expected-warning {{Undefined or garbage value returned to caller}} +} + +// Test to see if CXXTemporaryObjectExpr invalidates arguments. +int tempobj2() +{ + int j; + X a = X( &j, 1 ); + + return j; // no-warning +} + + +// Test for correct handling of C++ ForRange statement. +void test1() { + int array[2] = { 1, 2 }; + int j = 0; + for ( int i : array ) + j += i; + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} +} + +void test2() { + int array[2] = { 1, 2 }; + int j = 0; + for (int i : array) + j += i; + if (j == 3) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +// Do not crash on the following when constructing the +// callgraph. +struct RDar11178609 { + ~RDar11178609() = delete; +}; diff --git a/clang/test/Analysis/misc-ps-eager-assume.m b/clang/test/Analysis/misc-ps-eager-assume.m new file mode 100644 index 0000000..0aff8e4 --- /dev/null +++ b/clang/test/Analysis/misc-ps-eager-assume.m @@ -0,0 +1,146 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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 <NSObject> {} ++ (id)alloc; +- (id)init; +@end typedef struct {} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (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 <rdar://problem/6619921> +// +// 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 +} + + +//===---------------------------------------------------------------------===// +// <rdar://problem/7342806> +// This false positive occurred because the symbolic constraint on a short was +// not maintained via sign extension. The analyzer doesn't properly handle +// the sign extension, but now tracks the constraint. This particular +// case relies on -analyzer-eagerly-assume because of the expression +// 'Flag1 != Count > 0'. +//===---------------------------------------------------------------------===// + +void rdar7342806_aux(short x); + +void rdar7342806() { + extern short Count; + extern short Flag1; + + short *Pointer = 0; + short Flag2 = !!Pointer; // Flag2 is false (0). + short Ok = 1; + short Which; + + if( Flag1 != Count > 0 ) + // Static analyzer skips this so either + // Flag1 is true and Count > 0 + // or + // Flag1 is false and Count <= 0 + Ok = 0; + + if( Flag1 != Flag2 ) + // Analyzer skips this so Flag1 and Flag2 have the + // same value, both are false because Flag2 is false. And + // from that we know Count must be <= 0. + Ok = 0; + + for( Which = 0; + Which < Count && Ok; + Which++ ) + // This statement can only execute if Count > 0 which can only + // happen when Flag1 and Flag2 are both true and Flag2 will only + // be true when Pointer is not NULL. + rdar7342806_aux(*Pointer); // no-warning +} + +//===---------------------------------------------------------------------===// +// PR 5627 - http://llvm.org/bugs/show_bug.cgi?id=5627 +// This test case depends on using -analyzer-eagerly-assume and +// -analyzer-store=region. The '-analyzer-eagerly-assume' causes the path +// to bifurcate when evaluating the function call argument, and a state +// caching bug in GRExprEngine::CheckerVisit (and friends) caused the store +// to 'p' to not be evaluated along one path, but then an autotransition caused +// the path to keep on propagating with 'p' still set to an undefined value. +// We would then get a bogus report of returning uninitialized memory. +// Note: CheckerVisit mistakenly cleared an existing node, and the cleared +// node was resurrected by GRStmtNodeBuilder::~GRStmtNodeBuilder(), where +// 'p' was not assigned. +//===---------------------------------------------------------------------===// + +float *pr5627_f(int y); + +float *pr5627_g(int x) { + float *p; + p = pr5627_f(!x); + return p; // no-warning +} + diff --git a/clang/test/Analysis/misc-ps-ranges.m b/clang/test/Analysis/misc-ps-ranges.m new file mode 100644 index 0000000..00337f4 --- /dev/null +++ b/clang/test/Analysis/misc-ps-ranges.m @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s + +// <rdar://problem/6776949> +// 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<argc;i++){ + p = &x; + } + + return *p; // no-warning +} + +// PR 5969: the comparison of argc < 3 || argc > 4 should constraint the switch +// statement from having the 'default' branch taken. This previously reported a false +// positive with the use of 'v'. + +int pr5969(int argc, char *argv[]) { + + int v; + + if ((argc < 3) || (argc > 4)) return 0; + + switch(argc) { + case 3: + v = 33; + break; + case 4: + v = 44; + break; + } + + return v; // no-warning +} + +int pr5969_positive(int argc, char *argv[]) { + + int v; + + if ((argc < 3) || (argc > 4)) return 0; + + switch(argc) { + case 3: + v = 33; + break; + } + + return v; // expected-warning{{Undefined or garbage value returned to caller}} +} diff --git a/clang/test/Analysis/misc-ps-region-store-i386.m b/clang/test/Analysis/misc-ps-region-store-i386.m new file mode 100644 index 0000000..3106a24 --- /dev/null +++ b/clang/test/Analysis/misc-ps-region-store-i386.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s + +// Here is a case where a pointer is treated as integer, invalidated as an +// integer, and then used again as a pointer. This test just makes sure +// we don't crash. +typedef unsigned uintptr_t; +void test_pointer_invalidated_as_int_aux(uintptr_t* ptr); +void test_pointer_invalidated_as_int() { + void *x; + test_pointer_invalidated_as_int_aux((uintptr_t*) &x); + // Here we have a pointer to integer cast. + uintptr_t y = (uintptr_t) x; +} + diff --git a/clang/test/Analysis/misc-ps-region-store-x86_64.m b/clang/test/Analysis/misc-ps-region-store-x86_64.m new file mode 100644 index 0000000..2c604cf --- /dev/null +++ b/clang/test/Analysis/misc-ps-region-store-x86_64.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s + +// Here is a case where a pointer is treated as integer, invalidated as an +// integer, and then used again as a pointer. This test just makes sure +// we don't crash. +typedef unsigned long uintptr_t; +void test_pointer_invalidated_as_int_aux(uintptr_t* ptr); +void test_pointer_invalidated_as_int() { + void *x; + test_pointer_invalidated_as_int_aux((uintptr_t*) &x); + // Here we have a pointer to integer cast. + uintptr_t y = (uintptr_t) x; +} + diff --git a/clang/test/Analysis/misc-ps-region-store.cpp b/clang/test/Analysis/misc-ps-region-store.cpp new file mode 100644 index 0000000..8d75fb8 --- /dev/null +++ b/clang/test/Analysis/misc-ps-region-store.cpp @@ -0,0 +1,580 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions + +// Test basic handling of references. +char &test1_aux(); +char *test1() { + return &test1_aux(); +} + +// Test test1_aux() evaluates to char &. +char test1_as_rvalue() { + return test1_aux(); +} + +// Test passing a value as a reference. The 'const' in test2_aux() adds +// an ImplicitCastExpr, which is evaluated as an lvalue. +int test2_aux(const int &n); +int test2(int n) { + return test2_aux(n); +} + +int test2_b_aux(const short &n); +int test2_b(int n) { + return test2_b_aux(n); +} + +// Test getting the lvalue of a derived and converting it to a base. This +// previously crashed. +class Test3_Base {}; +class Test3_Derived : public Test3_Base {}; + +int test3_aux(Test3_Base &x); +int test3(Test3_Derived x) { + return test3_aux(x); +} + +//===---------------------------------------------------------------------===// +// Test CFG support for C++ condition variables. +//===---------------------------------------------------------------------===// + +int test_init_in_condition_aux(); +int test_init_in_condition() { + if (int x = test_init_in_condition_aux()) { // no-warning + return 1; + } + return 0; +} + +int test_init_in_condition_switch() { + switch (int x = test_init_in_condition_aux()) { // no-warning + case 1: + return 0; + case 2: + if (x == 2) + return 0; + else { + // Unreachable. + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } + default: + break; + } + return 0; +} + +int test_init_in_condition_while() { + int z = 0; + while (int x = ++z) { // no-warning + if (x == 2) + break; + } + + if (z == 2) + return 0; + + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 0; +} + + +int test_init_in_condition_for() { + int z = 0; + for (int x = 0; int y = ++z; ++x) { + if (x == y) // no-warning + break; + } + if (z == 1) + return 0; + + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 0; +} + +//===---------------------------------------------------------------------===// +// Test handling of 'this' pointer. +//===---------------------------------------------------------------------===// + +class TestHandleThis { + int x; + + TestHandleThis(); + int foo(); + int null_deref_negative(); + int null_deref_positive(); +}; + +int TestHandleThis::foo() { + // Assume that 'x' is initialized. + return x + 1; // no-warning +} + +int TestHandleThis::null_deref_negative() { + x = 10; + if (x == 10) { + return 1; + } + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 0; +} + +int TestHandleThis::null_deref_positive() { + x = 10; + if (x == 9) { + return 1; + } + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{null pointer}} + return 0; +} + +// PR 7675 - passing literals by-reference +void pr7675(const double &a); +void pr7675(const int &a); +void pr7675(const char &a); +void pr7675_i(const _Complex double &a); + +void pr7675_test() { + pr7675(10.0); + pr7675(10); + pr7675('c'); + pr7675_i(4.0i); + // Add null deref to ensure we are analyzing the code up to this point. + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{null pointer}} +} + +// <rdar://problem/8375510> - CFGBuilder should handle temporaries. +struct R8375510 { + R8375510(); + ~R8375510(); + R8375510 operator++(int); +}; + +int r8375510(R8375510 x, R8375510 y) { + for (; ; x++) { } +} + +// PR8419 -- this used to crash. + +class String8419 { + public: + char& get(int n); + char& operator[](int n); +}; + +char& get8419(); + +void Test8419() { + String8419 s; + ++(s.get(0)); + get8419()--; // used to crash + --s[0]; // used to crash + s[0] &= 1; // used to crash + s[0]++; // used to crash +} + +// PR8426 -- this used to crash. + +void Use(void* to); + +template <class T> class Foo { + ~Foo(); + struct Bar; + Bar* bar_; +}; + +template <class T> Foo<T>::~Foo() { + Use(bar_); + T::DoSomething(); + bar_->Work(); +} + +// PR8427 -- this used to crash. + +class Dummy {}; + +bool operator==(Dummy, int); + +template <typename T> +class Foo2 { + bool Bar(); +}; + +template <typename T> +bool Foo2<T>::Bar() { + return 0 == T(); +} + +// PR8433 -- this used to crash. + +template <typename T> +class Foo3 { + public: + void Bar(); + void Baz(); + T value_; +}; + +template <typename T> +void Foo3<T>::Bar() { + Baz(); + value_(); +} + +//===---------------------------------------------------------------------===// +// Handle misc. C++ constructs. +//===---------------------------------------------------------------------===// + +namespace fum { + int i = 3; +}; + +void test_namespace() { + // Previously triggered a crash. + using namespace fum; + int x = i; +} + +// Test handling methods that accept references as parameters, and that +// variables are properly invalidated. +class RDar9203355 { + bool foo(unsigned valA, long long &result) const; + bool foo(unsigned valA, int &result) const; +}; +bool RDar9203355::foo(unsigned valA, int &result) const { + long long val; + if (foo(valA, val) || + (int)val != val) // no-warning + return true; + result = val; // no-warning + return false; +} + +// Test handling of new[]. +void rdar9212512() { + int *x = new int[10]; + for (unsigned i = 0 ; i < 2 ; ++i) { + // This previously triggered an uninitialized values warning. + x[i] = 1; // no-warning + } +} + +// Test basic support for dynamic_cast<>. +struct Rdar9212495_C { virtual void bar() const; }; +class Rdar9212495_B : public Rdar9212495_C {}; +class Rdar9212495_A : public Rdar9212495_B {}; +const Rdar9212495_A& rdar9212495(const Rdar9212495_C* ptr) { + const Rdar9212495_A& val = dynamic_cast<const Rdar9212495_A&>(*ptr); + + if (&val == 0) { + val.bar(); // FIXME: This should eventually be a null dereference. + } + + return val; +} + +// Test constructors invalidating arguments. Previously this raised +// an uninitialized value warning. +extern "C" void __attribute__((noreturn)) PR9645_exit(int i); + +class PR9645_SideEffect +{ +public: + PR9645_SideEffect(int *pi); // caches pi in i_ + void Read(int *pi); // copies *pi into *i_ +private: + int *i_; +}; + +void PR9645() { + int i; + + PR9645_SideEffect se(&i); + int j = 1; + se.Read(&j); // this has a side-effect of initializing i. + + PR9645_exit(i); // no-warning +} + +PR9645_SideEffect::PR9645_SideEffect(int *pi) : i_(pi) {} +void PR9645_SideEffect::Read(int *pi) { *i_ = *pi; } + +// Invalidate fields during C++ method calls. +class RDar9267815 { + int x; + void test(); + void test_pos(); + void test2(); + void invalidate(); +}; + +void RDar9267815::test_pos() { + int *p = 0; + if (x == 42) + return; + *p = 0xDEADBEEF; // expected-warning {{null}} +} +void RDar9267815::test() { + int *p = 0; + if (x == 42) + return; + if (x == 42) + *p = 0xDEADBEEF; // no-warning +} + +void RDar9267815::test2() { + int *p = 0; + if (x == 42) + return; + invalidate(); + if (x == 42) + *p = 0xDEADBEEF; // expected-warning {{null}} +} + +// Test reference parameters. +void test_ref_double_aux(double &Value); +float test_ref_double() { + double dVal; + test_ref_double_aux(dVal); + // This previously warned because 'dVal' was thought to be uninitialized. + float Val = (float)dVal; // no-warning + return Val; +} + +// Test invalidation of class fields. +class TestInvalidateClass { +public: + int x; +}; + +void test_invalidate_class_aux(TestInvalidateClass &x); + +int test_invalidate_class() { + TestInvalidateClass y; + test_invalidate_class_aux(y); + return y.x; // no-warning +} + +// Test correct pointer arithmetic using 'p--'. This is to warn that we +// were loading beyond the written characters in buf. +char *RDar9269695(char *dst, unsigned int n) +{ + char buff[40], *p; + + p = buff; + do + *p++ = '0' + n % 10; + while (n /= 10); + + do + *dst++ = *--p; // no-warning + while (p != buff); + + return dst; +} + +// Test that we invalidate byref arguments passed to constructors. +class TestInvalidateInCtor { +public: + TestInvalidateInCtor(unsigned &x); +}; + +unsigned test_invalidate_in_ctor() { + unsigned x; + TestInvalidateInCtor foo(x); + return x; // no-warning +} +unsigned test_invalidate_in_ctor_new() { + unsigned x; + delete (new TestInvalidateInCtor(x)); + return x; // no-warning +} + +// Test assigning into a symbolic offset. +struct TestAssignIntoSymbolicOffset { + int **stuff[100]; + void test(int x, int y); +}; + +void TestAssignIntoSymbolicOffset::test(int x, int y) { + x--; + if (x > 8 || x < 0) + return; + if (stuff[x]) + return; + if (!stuff[x]) { + stuff[x] = new int*[y+1]; + // Previously triggered a null dereference. + stuff[x][y] = 0; // no-warning + } +} + +// Test loads from static fields. This previously triggered an uninitialized +// value warning. +class ClassWithStatic { +public: + static const unsigned value = 1; +}; + +int rdar9948787_negative() { + ClassWithStatic classWithStatic; + unsigned value = classWithStatic.value; + if (value == 1) + return 1; + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 0; +} + +int rdar9948787_positive() { + ClassWithStatic classWithStatic; + unsigned value = classWithStatic.value; + if (value == 0) + return 1; + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + return 0; +} + +// Regression test against global constants and switches. +enum rdar10202899_ValT { rdar10202899_ValTA, rdar10202899_ValTB, rdar10202899_ValTC }; +const rdar10202899_ValT val = rdar10202899_ValTA; +void rdar10202899_test1() { + switch (val) { + case rdar10202899_ValTA: {} + }; +} + +void rdar10202899_test2() { + if (val == rdar10202899_ValTA) + return; + int *p = 0; + *p = 0xDEADBEEF; +} + +void rdar10202899_test3() { + switch (val) { + case rdar10202899_ValTA: return; + default: ; + }; + int *p = 0; + *p = 0xDEADBEEF; +} + +// This used to crash the analyzer because of the unnamed bitfield. +void PR11249() +{ + struct { + char f1:4; + char :4; + char f2[1]; + char f3; + } V = { 1, {2}, 3 }; + int *p = 0; + if (V.f1 != 1) + *p = 0xDEADBEEF; // no-warning + if (V.f2[0] != 2) + *p = 0xDEADBEEF; // no-warning + if (V.f3 != 3) + *p = 0xDEADBEEF; // no-warning +} + +// Handle doing a load from the memory associated with the code for +// a function. +extern double nan( const char * ); +double PR11450() { + double NaN = *(double*) nan; + return NaN; +} + +// Test that 'this' is assumed non-null upon analyzing the entry to a "top-level" +// function (i.e., when not analyzing from a specific caller). +struct TestNullThis { + int field; + void test(); +}; + +void TestNullThis::test() { + int *p = &field; + if (p) + return; + field = 2; // no-warning +} + +// Test handling of 'catch' exception variables, and not warning +// about uninitialized values. +enum MyEnum { MyEnumValue }; +MyEnum rdar10892489() { + try { + throw MyEnumValue; + } catch (MyEnum e) { + return e; // no-warning + } + return MyEnumValue; +} + +MyEnum rdar10892489_positive() { + try { + throw MyEnumValue; + } catch (MyEnum e) { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + return e; + } + return MyEnumValue; +} + +// Test handling of catch with no condition variable. +void PR11545() { + try + { + throw; + } + catch (...) + { + } +} + +void PR11545_positive() { + try + { + throw; + } + catch (...) + { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + } +} + +// Test handling taking the address of a field. While the analyzer +// currently doesn't do anything intelligent here, this previously +// resulted in a crash. +class PR11146 { +public: + struct Entry; + void baz(); +}; + +struct PR11146::Entry { + int x; +}; + +void PR11146::baz() { + (void) &Entry::x; +} + +// Test symbolicating a reference. In this example, the +// analyzer (originally) didn't know how to handle x[index - index2], +// returning an UnknownVal. The conjured symbol wasn't a location, +// and would result in a crash. +void rdar10924675(unsigned short x[], int index, int index2) { + unsigned short &y = x[index - index2]; + if (y == 0) + return; +} diff --git a/clang/test/Analysis/misc-ps-region-store.m b/clang/test/Analysis/misc-ps-region-store.m new file mode 100644 index 0000000..d263d4d --- /dev/null +++ b/clang/test/Analysis/misc-ps-region-store.m @@ -0,0 +1,1343 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s + +typedef long unsigned int size_t; +void *memcpy(void *, const void *, size_t); +void *alloca(size_t); + +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 <NSObject> {} - (id)init; @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (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; + +#ifdef TEST_64 +typedef long long int64_t; +typedef int64_t intptr_t; +#else +typedef int int32_t; +typedef int32_t intptr_t; +#endif + +//--------------------------------------------------------------------------- +// 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; + // Since RegionStore doesn't handle unions yet, + // this branch condition won't be triggered + // as involving an uninitialized value. + if (((((__extension__ (((union { // no-warning + __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_help(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'; +} + +// BasicStore handles this case incorrectly because it doesn't reason about +// the value pointed to by 'x' and thus creates different symbolic values +// at the declarations of 'a' and 'b' respectively. RegionStore handles +// it correctly. See the companion test in 'misc-ps-basic-store.m'. +void test_trivial_symbolic_comparison_pointer_parameter(int *x) { + int a = *x; + int b = *x; + if (a != b) { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } +} + +// This is a modified test from 'misc-ps.m'. Here we have the extra +// NULL dereferences which are pruned out by RegionStore's symbolic reasoning +// of fields. +typedef struct _BStruct { void *grue; } BStruct; +void testB_aux(void *ptr); + +void testB(BStruct *b) { + { + int *__gruep__ = ((int *)&((b)->grue)); + int __gruev__ = *__gruep__; + int __gruev2__ = *__gruep__; + if (__gruev__ != __gruev2__) { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } + + testB_aux(__gruep__); + } + { + int *__gruep__ = ((int *)&((b)->grue)); + int __gruev__ = *__gruep__; + int __gruev2__ = *__gruep__; + if (__gruev__ != __gruev2__) { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } + + if (~0 != __gruev__) {} + } +} + +void testB_2(BStruct *b) { + { + int **__gruep__ = ((int **)&((b)->grue)); + int *__gruev__ = *__gruep__; + testB_aux(__gruep__); + } + { + int **__gruep__ = ((int **)&((b)->grue)); + int *__gruev__ = *__gruep__; + if ((int*)~0 != __gruev__) {} + } +} + +// This test case is a reduced case of a caching bug discovered by an +// assertion failure in RegionStoreManager::BindArray. Essentially the +// DeclStmt is evaluated twice, but on the second loop iteration the +// engine caches out. Previously a false transition would cause UnknownVal +// to bind to the variable, firing an assertion failure. This bug was fixed +// in r76262. +void test_declstmt_caching() { +again: + { + const char a[] = "I like to crash"; + goto again; + } +} + +//===----------------------------------------------------------------------===// +// Reduced test case from <rdar://problem/7114618>. +// Basically a null check is performed on the field value, which is then +// assigned to a variable and then checked again. +//===----------------------------------------------------------------------===// +struct s_7114618 { int *p; }; +void test_rdar_7114618(struct s_7114618 *s) { + if (s->p) { + int *p = s->p; + if (!p) { + // Infeasible + int *dead = 0; + *dead = 0xDEADBEEF; // no-warning + } + } +} + +// Test pointers increment correctly. +void f() { + int a[2]; + a[1] = 3; + int *p = a; + p++; + if (*p != 3) { + int *q = 0; + *q = 3; // no-warning + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7185607> +// Bit-fields of a struct should be invalidated when blasting the entire +// struct with an integer constant. +//===----------------------------------------------------------------------===// +struct test_7185607 { + int x : 10; + int y : 22; +}; +int rdar_test_7185607() { + struct test_7185607 s; // Uninitialized. + *((unsigned *) &s) = 0U; + return s.x; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7242006> [RegionStore] compound literal assignment with +// floats not honored +// This test case is mirrored in misc-ps.m, but this case is a negative. +//===----------------------------------------------------------------------===// +typedef float CGFloat; +typedef struct _NSSize { + CGFloat width; + CGFloat height; +} NSSize; + +CGFloat rdar7242006_negative(CGFloat x) { + NSSize y; + return y.width; // expected-warning{{garbage}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7249340> - Allow binding of values to symbolic regions. +// This test case shows how RegionStore tracks the value bound to 'x' +// after the assignment. +//===----------------------------------------------------------------------===// +typedef int* ptr_rdar_7249340; +void rdar_7249340(ptr_rdar_7249340 x) { + *x = 1; + if (*x) + return; + int *p = 0; // This is unreachable. + *p = 0xDEADBEEF; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7249327> - This test case tests both value tracking of +// array values and that we handle symbolic values that are casted +// between different integer types. Note the assignment 'n = *a++'; here +// 'n' is and 'int' and '*a' is 'unsigned'. Previously we got a false positive +// at 'x += *b++' (undefined value) because we got a false path. +//===----------------------------------------------------------------------===// +int rdar_7249327_aux(void); + +void rdar_7249327(unsigned int A[2*32]) { + int B[2*32]; + int *b; + unsigned int *a; + int x = 0; + + int n; + + a = A; + b = B; + + n = *a++; + if (n) + *b++ = rdar_7249327_aux(); + + a = A; + b = B; + + n = *a++; // expected-warning{{Assigned value is always the same as the existing value}} + if (n) + x += *b++; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6914474> - Check that 'x' is invalidated because its +// address is passed in as a value to a struct. +//===----------------------------------------------------------------------===// +struct doodad_6914474 { int *v; }; +extern void prod_6914474(struct doodad_6914474 *d); +int rdar_6914474(void) { + int x; + struct doodad_6914474 d; + d.v = &x; + prod_6914474(&d); + return x; // no-warning +} + +// Test invalidation of a single field. +struct s_test_field_invalidate { + int x; +}; +extern void test_invalidate_field(int *x); +int test_invalidate_field_test() { + struct s_test_field_invalidate y; + test_invalidate_field(&y.x); + return y.x; // no-warning +} +int test_invalidate_field_test_positive() { + struct s_test_field_invalidate y; + return y.x; // expected-warning{{garbage}} +} + +// This test case illustrates how a typeless array of bytes casted to a +// struct should be treated as initialized. RemoveDeadBindings previously +// had a bug that caused 'x' to lose its default symbolic value after the +// assignment to 'p', thus causing 'p->z' to evaluate to "undefined". +struct ArrayWrapper { unsigned char y[16]; }; +struct WrappedStruct { unsigned z; }; + +void test_handle_array_wrapper_helper(); + +int test_handle_array_wrapper() { + struct ArrayWrapper x; + test_handle_array_wrapper_helper(&x); + struct WrappedStruct *p = (struct WrappedStruct*) x.y; // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption.}} + return p->z; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7261075> [RegionStore] crash when +// handling load: '*((unsigned int *)"????")' +//===----------------------------------------------------------------------===// + +int rdar_7261075(void) { + unsigned int var = 0; + if (var == *((unsigned int *)"????")) + return 1; + return 0; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7275774> false path due to limited pointer +// arithmetic constraints +//===----------------------------------------------------------------------===// + +void rdar_7275774(void *data, unsigned n) { + if (!(data || n == 0)) + return; + + unsigned short *p = (unsigned short*) data; + unsigned short *q = p + (n / 2); + + if (p < q) { + // If we reach here, 'p' cannot be null. If 'p' is null, then 'n' must + // be '0', meaning that this branch is not feasible. + *p = *q; // no-warning + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7312221> +// +// Test that Objective-C instance variables aren't prematurely pruned +// from the analysis state. +//===----------------------------------------------------------------------===// + +struct rdar_7312221_value { int x; }; + +@interface RDar7312221 +{ + struct rdar_7312221_value *y; +} +- (void) doSomething_7312221; +@end + +extern struct rdar_7312221_value *rdar_7312221_helper(); +extern int rdar_7312221_helper_2(id o); +extern void rdar_7312221_helper_3(int z); + +@implementation RDar7312221 +- (void) doSomething_7312221 { + if (y == 0) { + y = rdar_7312221_helper(); + if (y != 0) { + y->x = rdar_7312221_helper_2(self); + // The following use of 'y->x' previously triggered a null dereference, as the value of 'y' + // before 'y = rdar_7312221_helper()' would be used. + rdar_7312221_helper_3(y->x); // no-warning + } + } +} +@end + +struct rdar_7312221_container { + struct rdar_7312221_value *y; +}; + +extern int rdar_7312221_helper_4(struct rdar_7312221_container *s); + +// This test case essentially matches the one in [RDar7312221 doSomething_7312221]. +void doSomething_7312221_with_struct(struct rdar_7312221_container *Self) { + if (Self->y == 0) { + Self->y = rdar_7312221_helper(); + if (Self->y != 0) { + Self->y->x = rdar_7312221_helper_4(Self); + rdar_7312221_helper_3(Self->y->x); // no-warning + } + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7332673> - Just more tests cases for regions +//===----------------------------------------------------------------------===// + +void rdar_7332673_test1() { + char value[1]; + if ( *(value) != 1 ) {} // expected-warning{{The left operand of '!=' is a garbage value}} +} +int rdar_7332673_test2_aux(char *x); +void rdar_7332673_test2() { + char *value; + if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{Function call argument is an uninitialized value}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7347252>: Because of a bug in +// RegionStoreManager::RemoveDeadBindings(), the symbol for s->session->p +// would incorrectly be pruned from the state after the call to +// rdar7347252_malloc1(), and would incorrectly result in a warning about +// passing a null pointer to rdar7347252_memcpy(). +//===----------------------------------------------------------------------===// + +struct rdar7347252_AA { char *p;}; +typedef struct { + struct rdar7347252_AA *session; + int t; + char *q; +} rdar7347252_SSL1; + +int rdar7347252_f(rdar7347252_SSL1 *s); +char *rdar7347252_malloc1(int); +char *rdar7347252_memcpy1(char *d, char *s, int n) __attribute__((nonnull (1,2))); + +int rdar7347252(rdar7347252_SSL1 *s) { + rdar7347252_f(s); // the SymbolicRegion of 's' is set a default binding of conjured symbol + if (s->session->p == ((void*)0)) { + if ((s->session->p = rdar7347252_malloc1(10)) == ((void*)0)) { + return 0; + } + rdar7347252_memcpy1(s->session->p, "aa", 2); // no-warning + } + return 0; +} + +//===----------------------------------------------------------------------===// +// PR 5316 - "crash when accessing field of lazy compound value" +// Previously this caused a crash at the MemberExpr '.chr' when loading +// a field value from a LazyCompoundVal +//===----------------------------------------------------------------------===// + +typedef unsigned int pr5316_wint_t; +typedef pr5316_wint_t pr5316_REFRESH_CHAR; +typedef struct { + pr5316_REFRESH_CHAR chr; +} +pr5316_REFRESH_ELEMENT; +static void pr5316(pr5316_REFRESH_ELEMENT *dst, const pr5316_REFRESH_ELEMENT *src) { + while ((*dst++ = *src++).chr != L'\0') ; +} + +//===----------------------------------------------------------------------===// +// Exercise creating ElementRegion with symbolic super region. +//===----------------------------------------------------------------------===// +void element_region_with_symbolic_superregion(int* p) { + int *x; + int a; + if (p[0] == 1) + x = &a; + if (p[0] == 1) + (void)*x; // no-warning +} + +//===----------------------------------------------------------------------===// +// Test returning an out-of-bounds pointer (CWE-466) +//===----------------------------------------------------------------------===// + +static int test_cwe466_return_outofbounds_pointer_a[10]; +int *test_cwe466_return_outofbounds_pointer() { + int *p = test_cwe466_return_outofbounds_pointer_a+10; + return p; // expected-warning{{Returned pointer value points outside the original object}} +} + +//===----------------------------------------------------------------------===// +// PR 3135 - Test case that shows that a variable may get invalidated when its +// address is included in a structure that is passed-by-value to an unknown function. +//===----------------------------------------------------------------------===// + +typedef struct { int *a; } pr3135_structure; +int pr3135_bar(pr3135_structure *x); +int pr3135() { + int x; + pr3135_structure y = { &x }; + // the call to pr3135_bar may initialize x + if (pr3135_bar(&y) && x) // no-warning + return 1; + return 0; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7403269> - Test that we handle compound initializers with +// partially unspecified array values. Previously this caused a crash. +//===----------------------------------------------------------------------===// + +typedef struct RDar7403269 { + unsigned x[10]; + unsigned y; +} RDar7403269; + +void rdar7403269() { + RDar7403269 z = { .y = 0 }; + if (z.x[4] == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +typedef struct RDar7403269_b { + struct zorg { int w; int k; } x[10]; + unsigned y; +} RDar7403269_b; + +void rdar7403269_b() { + RDar7403269_b z = { .y = 0 }; + if (z.x[5].w == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +void rdar7403269_b_pos() { + RDar7403269_b z = { .y = 0 }; + if (z.x[5].w == 1) + return; + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} +} + + +//===----------------------------------------------------------------------===// +// Test that incrementing a non-null pointer results in a non-null pointer. +// (<rdar://problem/7191542>) +//===----------------------------------------------------------------------===// + +void test_increment_nonnull_rdar_7191542(const char *path) { + const char *alf = 0; + + for (;;) { + // When using basic-store, we get a null dereference here because we lose information + // about path after the pointer increment. + char c = *path++; // no-warning + if (c == 'a') { + alf = path; + } + + if (alf) + return; + } +} + +//===----------------------------------------------------------------------===// +// Test that the store (implicitly) tracks values for doubles/floats that are +// uninitialized (<rdar://problem/6811085>) +//===----------------------------------------------------------------------===// + +double rdar_6811085(void) { + double u; + return u + 10; // expected-warning{{The left operand of '+' is a garbage value}} +} + +//===----------------------------------------------------------------------===// +// Path-sensitive tests for blocks. +//===----------------------------------------------------------------------===// + +void indirect_block_call(void (^f)()); + +int blocks_1(int *p, int z) { + __block int *q = 0; + void (^bar)() = ^{ q = p; }; + + if (z == 1) { + // The call to 'bar' might cause 'q' to be invalidated. + bar(); + *q = 0x1; // no-warning + } + else if (z == 2) { + // The function 'indirect_block_call' might invoke bar, thus causing + // 'q' to possibly be invalidated. + indirect_block_call(bar); + *q = 0x1; // no-warning + } + else { + *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} + } + return z; +} + +int blocks_2(int *p, int z) { + int *q = 0; + void (^bar)(int **) = ^(int **r){ *r = p; }; + + if (z) { + // The call to 'bar' might cause 'q' to be invalidated. + bar(&q); + *q = 0x1; // no-warning + } + else { + *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} + } + return z; +} + +// Test that the value of 'x' is considered invalidated after the block +// is passed as an argument to the message expression. +typedef void (^RDar7582031CB)(void); +@interface RDar7582031 +- rdar7582031:RDar7582031CB; +- rdar7582031_b:RDar7582031CB; +@end + +// Test with one block. +unsigned rdar7582031(RDar7582031 *o) { + __block unsigned x; + [o rdar7582031:^{ x = 1; }]; + return x; // no-warning +} + +// Test with two blocks. +unsigned long rdar7582031_b(RDar7582031 *o) { + __block unsigned y; + __block unsigned long x; + [o rdar7582031:^{ y = 1; }]; + [o rdar7582031_b:^{ x = 1LL; }]; + return x + (unsigned long) y; // no-warning +} + +// Show we get an error when 'o' is null because the message +// expression has no effect. +unsigned long rdar7582031_b2(RDar7582031 *o) { + __block unsigned y; + __block unsigned long x; + if (o) + return 1; + [o rdar7582031:^{ y = 1; }]; + [o rdar7582031_b:^{ x = 1LL; }]; + return x + (unsigned long) y; // expected-warning{{The left operand of '+' is a garbage value}} +} + +// Show that we handle static variables also getting invalidated. +void rdar7582031_aux(void (^)(void)); +RDar7582031 *rdar7582031_aux_2(); + +unsigned rdar7582031_static() { + static RDar7582031 *o = 0; + rdar7582031_aux(^{ o = rdar7582031_aux_2(); }); + + __block unsigned x; + [o rdar7582031:^{ x = 1; }]; + return x; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7462324> - Test that variables passed using __blocks +// are not treated as being uninitialized. +//===----------------------------------------------------------------------===// + +typedef void (^RDar_7462324_Callback)(id obj); + +@interface RDar7462324 +- (void) foo:(id)target; +- (void) foo_positive:(id)target; + +@end + +@implementation RDar7462324 +- (void) foo:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + if (object) { + builder(self); // no-warning + } + }; + builder(target); +} +- (void) foo_positive:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + id x; + if (object) { + builder(x); // expected-warning{{Function call argument is an uninitialized value}} + } + }; + builder(target); +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/7468209> - Scanning for live variables within a block should +// not crash on variables passed by reference via __block. +//===----------------------------------------------------------------------===// + +int rdar7468209_aux(); +void rdar7468209_aux_2(); + +void rdar7468209() { + __block int x = 0; + ^{ + x = rdar7468209_aux(); + // We need a second statement so that 'x' would be removed from the store if it wasn't + // passed by reference. + rdar7468209_aux_2(); + }(); +} + +//===----------------------------------------------------------------------===// +// PR 5857 - Test loading an integer from a byte array that has also been +// reinterpreted to be loaded as a field. +//===----------------------------------------------------------------------===// + +typedef struct { int x; } TestFieldLoad; +int pr5857(char *src) { + TestFieldLoad *tfl = (TestFieldLoad *) (intptr_t) src; + int y = tfl->x; + long long *z = (long long *) (intptr_t) src; + long long w = 0; + int n = 0; + for (n = 0; n < y; ++n) { + // Previously we crashed analyzing this statement. + w = *z++; + } + return 1; +} + +//===----------------------------------------------------------------------===// +// PR 4358 - Without field-sensitivity, this code previously triggered +// a false positive that 'uninit' could be uninitialized at the call +// to pr4358_aux(). +//===----------------------------------------------------------------------===// + +struct pr4358 { + int bar; + int baz; +}; +void pr4358_aux(int x); +void pr4358(struct pr4358 *pnt) { + int uninit; + if (pnt->bar < 3) { + uninit = 1; + } else if (pnt->baz > 2) { + uninit = 3; + } else if (pnt->baz <= 2) { + uninit = 2; + } + pr4358_aux(uninit); // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7526777> +// Test handling fields of values returned from function calls or +// message expressions. +//===----------------------------------------------------------------------===// + +typedef struct testReturn_rdar_7526777 { + int x; + int y; +} testReturn_rdar_7526777; + +@interface TestReturnStruct_rdar_7526777 +- (testReturn_rdar_7526777) foo; +@end + +int test_return_struct(TestReturnStruct_rdar_7526777 *x) { + return [x foo].x; +} + +testReturn_rdar_7526777 test_return_struct_2_aux_rdar_7526777(); + +int test_return_struct_2_rdar_7526777() { + return test_return_struct_2_aux_rdar_7526777().x; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7527292> Assertion failed: (Op == BinaryOperator::Add || +// Op == BinaryOperator::Sub) +// This test case previously triggered an assertion failure due to a discrepancy +// been the loaded/stored value in the array +//===----------------------------------------------------------------------===// + +_Bool OSAtomicCompareAndSwapPtrBarrier( void *__oldValue, void *__newValue, void * volatile *__theValue ); + +void rdar_7527292() { + static id Cache7527292[32]; + for (signed long idx = 0; + idx < 32; + idx++) { + id v = Cache7527292[idx]; + if (v && OSAtomicCompareAndSwapPtrBarrier(v, ((void*)0), (void * volatile *)(Cache7527292 + idx))) { + } + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7515938> - Handle initialization of incomplete arrays +// in structures using a compound value. Previously this crashed. +//===----------------------------------------------------------------------===// + +struct rdar_7515938 { + int x; + int y[]; +}; + +const struct rdar_7515938 *rdar_7515938() { + static const struct rdar_7515938 z = { 0, { 1, 2 } }; + if (z.y[0] != 1) { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } + return &z; +} + +struct rdar_7515938_str { + int x; + char y[]; +}; + +const struct rdar_7515938_str *rdar_7515938_str() { + static const struct rdar_7515938_str z = { 0, "hello" }; + return &z; +} + +//===----------------------------------------------------------------------===// +// Assorted test cases from PR 4172. +//===----------------------------------------------------------------------===// + +struct PR4172A_s { int *a; }; + +void PR4172A_f2(struct PR4172A_s *p); + +int PR4172A_f1(void) { + struct PR4172A_s m; + int b[4]; + m.a = b; + PR4172A_f2(&m); + return b[3]; // no-warning +} + +struct PR4172B_s { int *a; }; + +void PR4172B_f2(struct PR4172B_s *p); + +int PR4172B_f1(void) { + struct PR4172B_s m; + int x; + m.a = &x; + PR4172B_f2(&m); + return x; // no-warning +} + +//===----------------------------------------------------------------------===// +// Test invalidation of values in struct literals. +//===----------------------------------------------------------------------===// + +struct s_rev96062 { int *x; int *y; }; +struct s_rev96062_nested { struct s_rev96062 z; }; + +void test_a_rev96062_aux(struct s_rev96062 *s); +void test_a_rev96062_aux2(struct s_rev96062_nested *s); + +int test_a_rev96062() { + int a, b; + struct s_rev96062 x = { &a, &b }; + test_a_rev96062_aux(&x); + return a + b; // no-warning +} +int test_b_rev96062() { + int a, b; + struct s_rev96062 x = { &a, &b }; + struct s_rev96062 z = x; + test_a_rev96062_aux(&z); + return a + b; // no-warning +} +int test_c_rev96062() { + int a, b; + struct s_rev96062 x = { &a, &b }; + struct s_rev96062_nested w = { x }; + struct s_rev96062_nested z = w; + test_a_rev96062_aux2(&z); + return a + b; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7242010> - The access to y[0] at the bottom previously +// was reported as an uninitialized value. +//===----------------------------------------------------------------------===// + +char *rdar_7242010(int count, char **y) { + char **x = alloca((count + 4) * sizeof(*x)); + x[0] = "hi"; + x[1] = "there"; + x[2] = "every"; + x[3] = "body"; + memcpy(x + 4, y, count * sizeof(*x)); + y = x; + return y[0]; // no-warning +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7770737> +//===----------------------------------------------------------------------===// + +struct rdar_7770737_s { intptr_t p; }; +void rdar_7770737_aux(struct rdar_7770737_s *p); +int rdar_7770737(void) +{ + int x; + + // Previously 'f' was not properly invalidated, causing the use of + // an uninitailized value below. + struct rdar_7770737_s f = { .p = (intptr_t)&x }; + rdar_7770737_aux(&f); + return x; // no-warning +} +int rdar_7770737_pos(void) +{ + int x; + struct rdar_7770737_s f = { .p = (intptr_t)&x }; + return x; // expected-warning{{Undefined or garbage value returned to caller}} +} + +//===----------------------------------------------------------------------===// +// Test handling of the implicit 'isa' field. For now we don't do anything +// interesting. +//===----------------------------------------------------------------------===// + +void pr6302(id x, Class y) { + // This previously crashed the analyzer (reported in PR 6302) + x->isa = y; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}} +} + +//===----------------------------------------------------------------------===// +// Specially handle global variables that are declared constant. In the +// example below, this forces the loop to take exactly 2 iterations. +//===----------------------------------------------------------------------===// + +const int pr6288_L_N = 2; +void pr6288_(void) { + int x[2]; + int *px[2]; + int i; + for (i = 0; i < pr6288_L_N; i++) + px[i] = &x[i]; + *(px[0]) = 0; // no-warning +} + +void pr6288_pos(int z) { + int x[2]; + int *px[2]; + int i; + for (i = 0; i < z; i++) + px[i] = &x[i]; // expected-warning{{Access out-of-bound array element (buffer overflow)}} + *(px[0]) = 0; // expected-warning{{Dereference of undefined pointer value}} +} + +void pr6288_b(void) { + const int L_N = 2; + int x[2]; + int *px[2]; + int i; + for (i = 0; i < L_N; i++) + px[i] = &x[i]; + *(px[0]) = 0; // no-warning +} + +// <rdar://problem/7817800> - A bug in RemoveDeadBindings was causing instance variable bindings +// to get prematurely pruned from the state. +@interface Rdar7817800 { + char *x; +} +- (void) rdar7817800_baz; +@end + +char *rdar7817800_foobar(); +void rdar7817800_qux(void*); + +@implementation Rdar7817800 +- (void) rdar7817800_baz { + if (x) + rdar7817800_qux(x); + x = rdar7817800_foobar(); + // Previously this triggered a bogus null dereference warning. + x[1] = 'a'; // no-warning +} +@end + +// PR 6036 - This test case triggered a crash inside StoreManager::CastRegion because the size +// of 'unsigned long (*)[0]' is 0. +struct pr6036_a { int pr6036_b; }; +struct pr6036_c; +void u132monitk (struct pr6036_c *pr6036_d) { + (void) ((struct pr6036_a *) (unsigned long (*)[0]) ((char *) pr6036_d - 1))->pr6036_b; // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption}} +} + +// <rdar://problem/7813989> - ?-expressions used as a base of a member expression should be treated as an lvalue +typedef struct rdar7813989_NestedVal { int w; } rdar7813989_NestedVal; +typedef struct rdar7813989_Val { rdar7813989_NestedVal nv; } rdar7813989_Val; + +int rdar7813989(int x, rdar7813989_Val *a, rdar7813989_Val *b) { + // This previously crashed with an assertion failure. + int z = (x ? a->nv : b->nv).w; + return z + 1; +} + +// PR 6844 - Don't crash on vaarg expression. +typedef __builtin_va_list va_list; +void map(int srcID, ...) { + va_list ap; + int i; + for (i = 0; i < srcID; i++) { + int v = __builtin_va_arg(ap, int); + } +} + +// PR 6854 - crash when casting symbolic memory address to a float +// Handle casting from a symbolic region to a 'float'. This isn't +// really all that intelligent, but previously this caused a crash +// in SimpleSValuator. +void pr6854(void * arg) { + void * a = arg; + *(void**)a = arg; + float f = *(float*) a; +} + +// <rdar://problem/8032791> False positive due to symbolic store not find +// value because of 'const' qualifier +double rdar_8032791_2(); +double rdar_8032791_1() { + struct R8032791 { double x[2]; double y; } + data[3] = { + {{1.0, 3.0}, 3.0}, // 1 2 3 + {{1.0, 1.0}, 0.0}, // 1 1 2 2 3 3 + {{1.0, 3.0}, 1.0} // 1 2 3 + }; + + double x = 0.0; + for (unsigned i = 0 ; i < 3; i++) { + const struct R8032791 *p = &data[i]; + x += p->y + rdar_8032791_2(); // no-warning + } + return x; +} + +// PR 7450 - Handle pointer arithmetic with __builtin_alloca +void pr_7450_aux(void *x); +void pr_7450() { + void *p = __builtin_alloca(10); + // Don't crash when analyzing the following statement. + pr_7450_aux(p + 8); +} + +// <rdar://problem/8243408> - Symbolicate struct values returned by value. +struct s_rdar_8243408 { int x; }; +extern struct s_rdar_8243408 rdar_8243408_aux(void); +void rdar_8243408(void) { + struct s_rdar_8243408 a = { 1 }, *b = 0; + while (a.x && !b) + a = rdar_8243408_aux(); + + // Previously there was a false error here with 'b' being null. + (void) (a.x && b->x); // no-warning + + // Introduce a null deref to ensure we are checking this path. + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} +} + +// <rdar://problem/8258814> +int r8258814() +{ + int foo; + int * a = &foo; + a[0] = 10; + // Do not warn that the value of 'foo' is uninitialized. + return foo; // no-warning +} + +// PR 8052 - Don't crash when reasoning about loads from a function address.\n +typedef unsigned int __uint32_t; +typedef unsigned long vm_offset_t; +typedef __uint32_t pd_entry_t; +typedef unsigned char u_char; +typedef unsigned int u_int; +typedef unsigned long u_long; +extern int bootMP_size; +void bootMP(void); +static void +pr8052(u_int boot_addr) +{ + int x; + int size = *(int *) ((u_long) & bootMP_size); + u_char *src = (u_char *) ((u_long) bootMP); + u_char *dst = (u_char *) boot_addr + ((vm_offset_t) ((((((((1 << +12) / (sizeof(pd_entry_t))) - 1) - 1) - (260 - 2))) << 22) | ((0) << 12))); + for (x = 0; + x < size; + ++x) + *dst++ = *src++; +} + +// PR 8015 - don't return undefined values for arrays when using a valid +// symbolic index +int pr8015_A(); +void pr8015_B(const char *); + +void pr8015_C() { + int number = pr8015_A(); + const char *numbers[] = { "zero" }; + if (number == 0) { + pr8015_B(numbers[number]); // no-warning + } +} + +// Tests that we correctly handle that 'number' is perfectly constrained +// after 'if (nunber == 0)', allowing us to resolve that +// numbers[number] == numbers[0]. +void pr8015_D_FIXME() { + int number = pr8015_A(); + const char *numbers[] = { "zero" }; + if (number == 0) { + if (numbers[number] == numbers[0]) // expected-warning{{Both operands to '==' always have the same value}} + return; + // Unreachable. + int *p = 0; + *p = 0xDEADBEEF; // no-warnng + } +} + +void pr8015_E() { + // Similar to pr8015_C, but number is allowed to be a valid range. + unsigned number = pr8015_A(); + const char *numbers[] = { "zero", "one", "two" }; + if (number < 3) { + pr8015_B(numbers[number]); // no-warning + } +} + +void pr8015_F_FIXME() { + // Similar to pr8015_E, but like pr8015_D we check if the pointer + // is the same as one of the string literals. The null dereference + // here is not feasible in practice, so this is a false positive. + int number = pr8015_A(); + const char *numbers[] = { "zero", "one", "two" }; + if (number < 3) { + const char *p = numbers[number]; + if (p == numbers[0] || p == numbers[1] || p == numbers[2]) + return; + int *q = 0; + *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} + } +} + +// PR 8141. Previously the statement expression in the for loop caused +// the CFG builder to crash. +struct list_pr8141 +{ + struct list_pr8141 *tail; +}; + +struct list_pr8141 * +pr8141 (void) { + struct list_pr8141 *items; + for (;; items = ({ do { } while (0); items->tail; })) // expected-warning{{Dereference of undefined pointer value}} + { + } +} + +// Don't crash when building the CFG. +void do_not_crash(int x) { + while (x - ({do {} while (0); x; })) { + } +} + +// <rdar://problem/8424269> - Handle looking at the size of a VLA in +// ArrayBoundChecker. Nothing intelligent (yet); just don't crash. +typedef struct RDar8424269_A { + int RDar8424269_C; +} RDar8424269_A; +static void RDar8424269_B(RDar8424269_A *p, unsigned char *RDar8424269_D, + const unsigned char *RDar8424269_E, int RDar8424269_F, + int b_w, int b_h, int dx, int dy) { + int x, y, b, r, l; + unsigned char tmp2t[3][RDar8424269_F * (32 + 8)]; + unsigned char *tmp2 = tmp2t[0]; + if (p && !p->RDar8424269_C) + b = 15; + tmp2 = tmp2t[1]; + if (b & 2) { // expected-warning{{The left operand of '&' is a garbage value}} + for (y = 0; y < b_h; y++) { + for (x = 0; x < b_w + 1; x++) { + int am = 0; + tmp2[x] = am; + } + } + } + tmp2 = tmp2t[2]; +} + +// <rdar://problem/8642434> - Handle transparent unions with the AttrNonNullChecker. +typedef union { + struct rdar_8642434_typeA *_dq; +} +rdar_8642434_typeB __attribute__((transparent_union)); + +__attribute__((visibility("default"))) __attribute__((__nonnull__)) __attribute__((__nothrow__)) +void rdar_8642434_funcA(rdar_8642434_typeB object); + +void rdar_8642434_funcB(struct rdar_8642434_typeA *x, struct rdar_8642434_typeA *y) { + rdar_8642434_funcA(x); + if (!y) + rdar_8642434_funcA(y); // expected-warning{{Null pointer passed as an argument to a 'nonnull' parameter}} +} + +// <rdar://problem/8848957> - Handle loads and stores from a symbolic index +// into array without warning about an uninitialized value being returned. +// While RegionStore can't fully reason about this example, it shouldn't +// warn here either. +typedef struct s_test_rdar8848957 { + int x, y, z; +} s_test_rdar8848957; + +s_test_rdar8848957 foo_rdar8848957(); +int rdar8848957(int index) { + s_test_rdar8848957 vals[10]; + vals[index] = foo_rdar8848957(); + return vals[index].x; // no-warning +} + +// PR 9049 - crash on symbolicating unions. This test exists solely to +// test that the analyzer doesn't crash. +typedef struct pr9048_cdev *pr9048_cdev_t; +typedef union pr9048_abstracted_disklabel { void *opaque; } pr9048_disklabel_t; +struct pr9048_diskslice { pr9048_disklabel_t ds_label; }; +struct pr9048_diskslices { + int dss_secmult; + struct pr9048_diskslice dss_slices[16]; +}; +void pr9048(pr9048_cdev_t dev, struct pr9048_diskslices * ssp, unsigned int slice) +{ + pr9048_disklabel_t lp; + struct pr9048_diskslice *sp; + sp = &ssp->dss_slices[slice]; + if (ssp->dss_secmult == 1) { + } else if ((lp = sp->ds_label).opaque != ((void *) 0)) { + } +} + +// Test Store reference counting in the presence of Lazy compound values. +// This previously caused an infinite recursion. +typedef struct {} Rdar_9103310_A; +typedef struct Rdar_9103310_B Rdar_9103310_B_t; +struct Rdar_9103310_B { + unsigned char Rdar_9103310_C[101]; +}; +void Rdar_9103310_E(Rdar_9103310_A * x, struct Rdar_9103310_C * b) { // expected-warning {{declaration of 'struct Rdar_9103310_C' will not be visible outside of this function}} + char Rdar_9103310_D[4][4] = { "a", "b", "c", "d"}; + int i; + Rdar_9103310_B_t *y = (Rdar_9103310_B_t *) x; + for (i = 0; i < 101; i++) { + Rdar_9103310_F(b, "%2d%s ", (y->Rdar_9103310_C[i]) / 4, Rdar_9103310_D[(y->Rdar_9103310_C[i]) % 4]); // expected-warning {{implicit declaration of function 'Rdar_9103310_F' is invalid in C99}} + } +} + +// Test handling binding lazy compound values to a region and then have +// specific elements have other bindings. +int PR9455() { + char arr[4] = "000"; + arr[0] = '1'; + if (arr[1] == '0') + return 1; + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 1; +} +int PR9455_2() { + char arr[4] = "000"; + arr[0] = '1'; + if (arr[1] == '0') { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + } + return 1; +} + +// Test initialization of substructs via lazy compound values. +typedef float RDar9163742_Float; + +typedef struct { + RDar9163742_Float x, y; +} RDar9163742_Point; +typedef struct { + RDar9163742_Float width, height; +} RDar9163742_Size; +typedef struct { + RDar9163742_Point origin; + RDar9163742_Size size; +} RDar9163742_Rect; + +extern RDar9163742_Rect RDar9163742_RectIntegral(RDar9163742_Rect); + +RDar9163742_Rect RDar9163742_IntegralRect(RDar9163742_Rect frame) +{ + RDar9163742_Rect integralFrame; + integralFrame.origin.x = frame.origin.x; + integralFrame.origin.y = frame.origin.y; + integralFrame.size = frame.size; + return RDar9163742_RectIntegral(integralFrame); // no-warning; all fields initialized +} + +// Test correct handling of prefix '--' operator. +void rdar9444714() { + int x; + char str[ 32 ]; + char buf[ 32 ]; + char * dst; + char * ptr; + + x = 1234; + dst = str; + ptr = buf; + do + { + *ptr++ = (char)( '0' + ( x % 10 ) ); + x /= 10; + } while( x > 0 ); + + while( ptr > buf ) + { + *dst++ = *( --( ptr ) ); // no-warning + } + *dst = '\0'; +} + +// Test handling symbolic elements with field accesses. +// <rdar://problem/11127008> +typedef struct { + unsigned value; +} RDar11127008; + +signed rdar_11127008_index(); + +static unsigned rdar_11127008(void) { + RDar11127008 values[] = {{.value = 0}, {.value = 1}}; + signed index = rdar_11127008_index(); + if (index < 0) return 0; + if (index >= 2) return 0; + return values[index].value; +} + diff --git a/clang/test/Analysis/misc-ps-region-store.mm b/clang/test/Analysis/misc-ps-region-store.mm new file mode 100644 index 0000000..8615c6a --- /dev/null +++ b/clang/test/Analysis/misc-ps-region-store.mm @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s + +//===------------------------------------------------------------------------------------------===// +// This files tests our path-sensitive handling of Objective-c++ files. +//===------------------------------------------------------------------------------------------===// + +// Test basic handling of references. +char &test1_aux(); +char *test1() { + return &test1_aux(); +} + +// Test test1_aux() evaluates to char &. +char test1_as_rvalue() { + return test1_aux(); +} + +// Test basic handling of references with Objective-C classes. +@interface Test1 +- (char&) foo; +@end + +char* Test1_harness(Test1 *p) { + return &[p foo]; +} + +char Test1_harness_b(Test1 *p) { + return [p foo]; +} + +// Basic test of C++ references with Objective-C pointers. +@interface RDar10569024 +@property(readonly) int x; +@end + +typedef RDar10569024* RDar10569024Ref; + +void rdar10569024_aux(RDar10569024Ref o); + +int rdar10569024(id p, id collection) { + for (id elem in collection) { + const RDar10569024Ref &o = (RDar10569024Ref) elem; + rdar10569024_aux(o); // no-warning + return o.x; // no-warning + } + return 0; +} diff --git a/clang/test/Analysis/misc-ps.c b/clang/test/Analysis/misc-ps.c new file mode 100644 index 0000000..f81b0dd --- /dev/null +++ b/clang/test/Analysis/misc-ps.c @@ -0,0 +1,128 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s + +int size_rdar9373039 = 1; +int foo_rdar9373039(const char *); + +int rdar93730392() { + int x; + int j = 0; + + for (int i = 0 ; i < size_rdar9373039 ; ++i) + x = 1; + + int extra = (2 + foo_rdar9373039 ("Clang") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("Clang")) % 4)) % 4)) + (2 + foo_rdar9373039 ("1.0") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("1.0")) % 4)) % 4)); // expected-warning {{never read}} + + for (int i = 0 ; i < size_rdar9373039 ; ++i) + j += x; // expected-warning {{garbage}} + + return j; +} + + +int PR8962 (int *t) { + // This should look through the __extension__ no-op. + if (__extension__ (t)) return 0; + return *t; // expected-warning {{null pointer}} +} + +int PR8962_b (int *t) { + // This should still ignore the nested casts + // which aren't handled by a single IgnoreParens() + if (((int)((int)t))) return 0; + return *t; // expected-warning {{null pointer}} +} + +int PR8962_c (int *t) { + // If the last element in a StmtExpr was a ParenExpr, it's still live + if (({ (t ? (_Bool)0 : (_Bool)1); })) return 0; + return *t; // no-warning +} + +int PR8962_d (int *t) { + // If the last element in a StmtExpr is an __extension__, it's still live + if (({ __extension__(t ? (_Bool)0 : (_Bool)1); })) return 0; + return *t; // no-warning +} + +int PR8962_e (int *t) { + // Redundant casts can mess things up! + // Environment used to skip through NoOp casts, but LiveVariables didn't! + if (({ (t ? (int)(int)0L : (int)(int)1L); })) return 0; + return *t; // no-warning +} + +int PR8962_f (int *t) { + // The StmtExpr isn't a block-level expression here, + // the __extension__ is. But the value should be attached to the StmtExpr + // anyway. Make sure the block-level check is /before/ IgnoreParens. + if ( __extension__({ + _Bool r; + if (t) r = 0; + else r = 1; + r; + }) ) return 0; + return *t; // no-warning +} + +// This previously crashed logic in the analyzer engine when evaluating locations. +void rdar10308201_aux(unsigned val); +void rdar10308201 (int valA, void *valB, unsigned valC) { + unsigned actual_base, lines; + if (valC == 0) { + actual_base = (unsigned)valB; + for (;;) { + if (valA & (1<<0)) + rdar10308201_aux(actual_base); + } + } +} + +typedef struct Struct103 { + unsigned i; +} Struct103; +typedef unsigned int size_t; +void __my_memset_chk(char*, int, size_t); +static int radar10367606(int t) { + Struct103 overall; + ((__builtin_object_size ((char *) &overall, 0) != (size_t) -1) ? __builtin___memset_chk ((char *) &overall, 0, sizeof(Struct103), __builtin_object_size ((char *) &overall, 0)) : __my_memset_chk ((char *) &overall, 0, sizeof(Struct103))); + return 0; +} + +/* Caching out on a sink node. */ +extern int fooR10376675(); +extern int* bazR10376675(); +extern int nR10376675; +void barR10376675(int *x) { + int *pm; + if (nR10376675 * 2) { + int *pk = bazR10376675(); + pm = pk; //expected-warning {{never read}} + } + do { + *x = fooR10376675(); + } while (0); +} + +// Test accesses to wide character strings doesn't break the analyzer. +typedef int wchar_t; +struct rdar10385775 { + wchar_t *name; +}; +void RDar10385775(struct rdar10385775* p) { + p->name = L"a"; +} + +// Test double loop of array and array literals. Previously this +// resulted in a false positive uninitailized value warning. +void rdar10686586() { + int array1[] = { 1, 2, 3, 0 }; + int array2[] = { 1, 2, 3, 0 }; + int *array[] = { array1, array2 }; + int sum = 0; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + sum += array[i][j]; // no-warning + } + } +} + diff --git a/clang/test/Analysis/misc-ps.m b/clang/test/Analysis/misc-ps.m new file mode 100644 index 0000000..9d2ff5b --- /dev/null +++ b/clang/test/Analysis/misc-ps.m @@ -0,0 +1,1347 @@ +// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued. +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s + +#ifndef __clang_analyzer__ +#error __clang_analyzer__ not defined +#endif + +typedef struct objc_ivar *Ivar; +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef int NSInteger; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSArray, 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 <NSObject> {} +- (id)init; ++ (id)allocWithZone:(NSZone *)zone; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end extern NSString * const NSBundleDidLoadNotification; +@interface NSValue : NSObject <NSCopying, NSCoding> +- (void)getValue:(void *)value; +@end +@interface NSNumber : NSValue +- (char)charValue; +- (id)initWithBool:(BOOL)value; +@end +@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 <rdar://problem/6253157> +@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 <rdar://problem/6268365> +// + +unsigned r6268365Aux(); + +void r6268365() { + unsigned x = 0; + x &= r6268365Aux(); // expected-warning{{The left operand to '&=' is always 0}} + unsigned j = 0; + + if (x == 0) ++j; + if (x == 0) x = x / j; // expected-warning{{Assigned value is always the same as the existing value}} expected-warning{{The right operand to '/' is always 1}} +} + +void divzeroassume(unsigned x, unsigned j) { + x /= j; + if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} + if (j == 0) x /= j; // no static-analyzer warning + if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} +} + +void divzeroassumeB(unsigned x, unsigned j) { + x = x / j; + if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} + if (j == 0) x /= j; // no static-analyzer warning + if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}} +} + +// 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{{Declared variable-length array (VLA) has zero size}} +} + +void check_uninit_sized_VLA() { + int x; + int vla[x]; // expected-warning{{Declared variable-length array (VLA) uses a garbage value as its 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 +} + +// check deference of undefined values +void check_deref_undef(void) { + int *p; + *p = 0xDEADBEEF; // expected-warning{{Dereference of undefined pointer value}} +} + +// 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) +void pr_3543(void) { + ({}); +} + +// <rdar://problem/6611677> +// 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]; } + +// <rdar://problem/6695527> - 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; +} + +// <rdar://problem/6708148> - 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}} +} + +// Check that the pointer-to-conts arguments do not get invalidated by Obj C +// interfaces. radar://10595327 +int rdar_10595327(char *str) { + char fl = str[0]; + int *p = 0; + NSString *s = [NSString stringWithUTF8String:str]; + if (str[0] != fl) + return *p; // no-warning + return 0; +} + +// For pointer arithmetic, --/++ should be treated as preserving non-nullness, +// regardless of how well the underlying StoreManager reasons about pointer +// arithmetic. +// <rdar://problem/6777209> +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) { + void *lbl = &&next_opcode; +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; +} + +// Test for <rdar://problem/7027684>. This just tests that the CFG is +// constructed correctly. Previously, the successor block of the entrance +// was the block containing the merge for '?', which would trigger an +// assertion failure. +int rdar_7027684_aux(); +int rdar_7027684_aux_2() __attribute__((noreturn)); +void rdar_7027684(int x, int y) { + {}; // this empty compound statement is critical. + (rdar_7027684_aux() ? rdar_7027684_aux_2() : (void) 0); +} + +// Test that we handle casts of string literals to arbitrary types. +unsigned const char *string_literal_test1() { + return (const unsigned char*) "hello"; +} + +const float *string_literal_test2() { + return (const float*) "hello"; +} + +// Test that we handle casts *from* incomplete struct types. +extern const struct _FooAssertStruct _cmd; +void test_cast_from_incomplete_struct_aux(volatile const void *x); +void test_cast_from_incomplete_struct() { + test_cast_from_incomplete_struct_aux(&_cmd); +} + +// Test for <rdar://problem/7034511> +// "ValueManager::makeIntVal(uint64_t X, QualType T) should return a 'Loc' +// when 'T' is a pointer" +// +// Previously this case would crash. +void test_rdar_7034511(NSArray *y) { + NSObject *x; + for (x in y) {} + if (x == ((void*) 0)) {} +} + +// Handle casts of function pointers (CodeTextRegions) to arbitrary pointer +// types. This was previously causing a crash in CastRegion. +void handle_funcptr_voidptr_casts() { + void **ptr; + typedef void *PVOID; + typedef void *PCHAR; + typedef long INT_PTR, *PINT_PTR; + typedef INT_PTR (*FARPROC)(); + FARPROC handle_funcptr_voidptr_casts_aux(); + PVOID handle_funcptr_voidptr_casts_aux_2(PVOID volatile *x); + PVOID handle_funcptr_voidptr_casts_aux_3(PCHAR volatile *x); + + ptr = (void**) handle_funcptr_voidptr_casts_aux(); + handle_funcptr_voidptr_casts_aux_2(ptr); + handle_funcptr_voidptr_casts_aux_3(ptr); +} + +// RegionStore::Retrieve previously crashed on this example. This example +// was previously in the test file 'xfail_regionstore_wine_crash.c'. +void testA() { + long x = 0; + char *y = (char *) &x; + if (!*y) + return; +} + +// RegionStoreManager previously crashed on this example. The problem is that +// the value bound to the field of b->grue after the call to testB_aux is +// a symbolic region. The second '*__gruep__' involves performing a load +// from a 'int*' that really is a 'void**'. The loaded location must be +// implicitly converted to an integer that wraps a location. Previosly we would +// get a crash here due to an assertion failure. +typedef struct _BStruct { void *grue; } BStruct; +void testB_aux(void *ptr); +void testB(BStruct *b) { + { + int *__gruep__ = ((int *)&((b)->grue)); + int __gruev__ = *__gruep__; + testB_aux(__gruep__); + } + { + int *__gruep__ = ((int *)&((b)->grue)); + int __gruev__ = *__gruep__; + if (~0 != __gruev__) {} + } +} + +void test_trivial_symbolic_comparison(int *x) { + int test_trivial_symbolic_comparison_aux(); + int a = test_trivial_symbolic_comparison_aux(); + int b = a; + if (a != b) { // expected-warning{{Both operands to '!=' always have the same value}} + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } + + a = a == 1; + b = b == 1; + if (a != b) { // expected-warning{{Both operands to '!=' always have the same value}} + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } +} + +// Test for: +// <rdar://problem/7062158> false positive null dereference due to +// BasicStoreManager not tracking *static* globals +// +// This just tests the proper tracking of symbolic values for globals (both +// static and non-static). +// +static int* x_rdar_7062158; +void rdar_7062158() { + int *current = x_rdar_7062158; + if (current == x_rdar_7062158) + return; + + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +int* x_rdar_7062158_2; +void rdar_7062158_2() { + int *current = x_rdar_7062158_2; + if (current == x_rdar_7062158_2) + return; + + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +// This test reproduces a case for a crash when analyzing ClamAV using +// RegionStoreManager (the crash doesn't exhibit in BasicStoreManager because +// it isn't doing anything smart about arrays). The problem is that on the +// second line, 'p = &p[i]', p is assigned an ElementRegion whose index +// is a 16-bit integer. On the third line, a new ElementRegion is created +// based on the previous region, but there the region uses a 32-bit integer, +// resulting in a clash of values (an assertion failure at best). We resolve +// this problem by implicitly converting index values to 'int' when the +// ElementRegion is created. +unsigned char test_array_index_bitwidth(const unsigned char *p) { + unsigned short i = 0; + for (i = 0; i < 2; i++) p = &p[i]; + return p[i+1]; +} + +// This case tests that CastRegion handles casts involving BlockPointerTypes. +// It should not crash. +void test_block_cast() { + id test_block_cast_aux(); + (void (^)(void *))test_block_cast_aux(); // expected-warning{{expression result unused}} +} + +int OSAtomicCompareAndSwap32Barrier(); + +// Test comparison of 'id' instance variable to a null void* constant after +// performing an OSAtomicCompareAndSwap32Barrier. +// This previously was a crash in RegionStoreManager. +@interface TestIdNull { + id x; +} +-(int)foo; +@end +@implementation TestIdNull +-(int)foo { + OSAtomicCompareAndSwap32Barrier(0, (signed)2, (signed*)&x); + if (x == (void*) 0) { return 0; } + return 1; +} +@end + +// PR 4594 - This was a crash when handling casts in SimpleSValuator. +void PR4594() { + char *buf[1]; + char **foo = buf; + *foo = "test"; +} + +// Test invalidation logic where an integer is casted to an array with a +// different sign and then invalidated. +void test_invalidate_cast_int() { + void test_invalidate_cast_int_aux(unsigned *i); + signed i; + test_invalidate_cast_int_aux((unsigned*) &i); + if (i < 0) + return; +} + +int ivar_getOffset(); + +// Reduced from a crash involving the cast of an Objective-C symbolic region to +// 'char *' +static NSNumber *test_ivar_offset(id self, SEL _cmd, Ivar inIvar) { + return [[[NSNumber allocWithZone:((void*)0)] initWithBool:*(_Bool *)((char *)self + ivar_getOffset(inIvar))] autorelease]; +} + +// Reduced from a crash in StoreManager::CastRegion involving a divide-by-zero. +// This resulted from not properly handling region casts to 'const void*'. +void test_cast_const_voidptr() { + char x[10]; + char *p = &x[1]; + const void* q = p; +} + +// Reduced from a crash when analyzing Wine. This test handles loads from +// function addresses. +typedef long (*FARPROC)(); +FARPROC test_load_func(FARPROC origfun) { + if (!*(unsigned char*) origfun) + return origfun; + return 0; +} + +// Test passing-by-value an initialized struct variable. +struct test_pass_val { + int x; + int y; +}; +void test_pass_val_aux(struct test_pass_val s); +void test_pass_val() { + struct test_pass_val s; + s.x = 1; + s.y = 2; + test_pass_val_aux(s); +} + +// This is a reduced test case of a false positive that previously appeared +// in RegionStoreManager. Previously the array access resulted in dereferencing +// an undefined value. +int test_array_compound(int *q, int *r, int *z) { + int *array[] = { q, r, z }; + int j = 0; + for (unsigned i = 0; i < 3 ; ++i) + if (*array[i]) ++j; // no-warning + return j; +} + +// symbolic value stored in 'x' wouldn't be implicitly casted to a signed value +// during the comparison. +int rdar_7124210(unsigned int x) { + enum { SOME_CONSTANT = 123 }; + int compare = ((signed) SOME_CONSTANT) == *((signed *) &x); + return compare ? 0 : 1; // Forces the evaluation of the symbolic constraint. +} + +void pr4781(unsigned long *raw1) { + unsigned long *cook, *raw0; + unsigned long dough[32]; + int i; + cook = dough; + for( i = 0; i < 16; i++, raw1++ ) { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + } +} + +// <rdar://problem/7185647> - 'self' should be treated as being non-null +// upon entry to an objective-c method. +@interface RDar7185647 +- (id)foo; +@end +@implementation RDar7185647 +- (id) foo { + if (self) + return self; + *((volatile int *) 0x0) = 0xDEADBEEF; // no-warning + return self; +} +@end + +// Test reasoning of __builtin_offsetof; +struct test_offsetof_A { + int x; + int y; +}; +struct test_offsetof_B { + int w; + int z; +}; +void test_offsetof_1() { + if (__builtin_offsetof(struct test_offsetof_A, x) == + __builtin_offsetof(struct test_offsetof_B, w)) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} +void test_offsetof_2() { + if (__builtin_offsetof(struct test_offsetof_A, y) == + __builtin_offsetof(struct test_offsetof_B, z)) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} +void test_offsetof_3() { + if (__builtin_offsetof(struct test_offsetof_A, y) - + __builtin_offsetof(struct test_offsetof_A, x) + == + __builtin_offsetof(struct test_offsetof_B, z) - + __builtin_offsetof(struct test_offsetof_B, w)) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} +void test_offsetof_4() { + if (__builtin_offsetof(struct test_offsetof_A, y) == + __builtin_offsetof(struct test_offsetof_B, w)) + return; + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} +} + +// <rdar://problem/6829164> "nil receiver" false positive: make tracking +// of the MemRegion for 'self' path-sensitive +@interface RDar6829164 : NSObject { + double x; int y; +} +- (id) init; +@end + +id rdar_6829164_1(); +double rdar_6829164_2(); + +@implementation RDar6829164 +- (id) init { + if((self = [super init]) != 0) { + id z = rdar_6829164_1(); + y = (z != 0); + if (y) + x = rdar_6829164_2(); + } + return self; +} +@end + +// <rdar://problem/7242015> - Invalidate values passed-by-reference +// to functions when the pointer to the value is passed as an integer. +void test_7242015_aux(unsigned long); +int rdar_7242015() { + int x; + test_7242015_aux((unsigned long) &x); // no-warning + return x; // Previously we return and uninitialized value when + // using RegionStore. +} + +// <rdar://problem/7242006> [RegionStore] compound literal assignment with +// floats not honored +CGFloat rdar7242006(CGFloat x) { + NSSize y = (NSSize){x, 10}; + return y.width; // no-warning +} + +// PR 4988 - This test exhibits a case where a function can be referenced +// when not explicitly used in an "lvalue" context (as far as the analyzer is +// concerned). This previously triggered a crash due to an invalid assertion. +void pr_4988(void) { + pr_4988; // expected-warning{{expression result unused}} +} + +// <rdar://problem/7152418> - A 'signed char' is used as a flag, which is +// implicitly converted to an int. +void *rdar7152418_bar(); +@interface RDar7152418 { + signed char x; +} +-(char)foo; +@end; +@implementation RDar7152418 +-(char)foo { + char *p = 0; + void *result = 0; + if (x) { + result = rdar7152418_bar(); + p = "hello"; + } + if (!result) { + result = rdar7152418_bar(); + if (result && x) + return *p; // no-warning + } + return 1; +} + +//===----------------------------------------------------------------------===// +// Test constant-folding of symbolic values, automatically handling type +// conversions of the symbol as necessary. +//===----------------------------------------------------------------------===// + +// Previously this would crash once we started eagerly evaluating symbols whose +// values were constrained to a single value. +void test_symbol_fold_1(signed char x) { + while (1) { + if (x == ((signed char) 0)) {} + } +} + +// This previously caused a crash because it triggered an assertion in APSInt. +void test_symbol_fold_2(unsigned int * p, unsigned int n, + const unsigned int * grumpkin, unsigned int dn) { + unsigned int i; + unsigned int tempsub[8]; + unsigned int *solgrumpkin = tempsub + n; + for (i = 0; i < n; i++) + solgrumpkin[i] = (i < dn) ? ~grumpkin[i] : 0xFFFFFFFF; + for (i <<= 5; i < (n << 5); i++) {} +} + +// This previously caused a crash because it triggered an assertion in APSInt. +// 'x' would evaluate to a 8-bit constant (because of the return value of +// test_symbol_fold_3_aux()) which would not get properly promoted to an +// integer. +char test_symbol_fold_3_aux(void); +unsigned test_symbol_fold_3(void) { + unsigned x = test_symbol_fold_3_aux(); + if (x == 54) + return (x << 8) | 0x5; + return 0; +} + +//===----------------------------------------------------------------------===// +// Tests for the warning of casting a non-struct type to a struct type +//===----------------------------------------------------------------------===// + +typedef struct {unsigned int v;} NSSwappedFloat; + +NSSwappedFloat test_cast_nonstruct_to_struct(float x) { + struct hodor { + float number; + NSSwappedFloat sf; + }; + return ((struct hodor *)&x)->sf; // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption}} +} + +NSSwappedFloat test_cast_nonstruct_to_union(float x) { + union bran { + float number; + NSSwappedFloat sf; + }; + return ((union bran *)&x)->sf; // no-warning +} + +void test_undefined_array_subscript() { + int i, a[10]; + int *p = &a[i]; // expected-warning{{Array subscript is undefined}} +} +@end + +//===----------------------------------------------------------------------===// +// Test using an uninitialized value as a branch condition. +//===----------------------------------------------------------------------===// + +int test_uninit_branch(void) { + int x; + if (x) // expected-warning{{Branch condition evaluates to a garbage value}} + return 1; + return 0; +} + +int test_uninit_branch_b(void) { + int x; + return x ? 1 : 0; // expected-warning{{Branch condition evaluates to a garbage value}} +} + +int test_uninit_branch_c(void) { + int x; + if ((short)x) // expected-warning{{Branch condition evaluates to a garbage value}} + return 1; + return 0; +} + +//===----------------------------------------------------------------------===// +// Test passing an undefined value in a message or function call. +//===----------------------------------------------------------------------===// + +void test_bad_call_aux(int x); +void test_bad_call(void) { + int y; + test_bad_call_aux(y); // expected-warning{{Function call argument is an uninitialized value}} +} + +@interface TestBadArg {} +- (void) testBadArg:(int) x; +@end + +void test_bad_msg(TestBadArg *p) { + int y; + [p testBadArg:y]; // expected-warning{{Argument in message expression is an uninitialized value}} +} + +//===----------------------------------------------------------------------===// +// PR 6033 - Test emitting the correct output in a warning where we use '%' +// with operands that are undefined. +//===----------------------------------------------------------------------===// + +int pr6033(int x) { + int y; + return x % y; // expected-warning{{The right operand of '%' is a garbage value}} +} + +struct trie { + struct trie* next; +}; + +struct kwset { + struct trie *trie; + unsigned char y[10]; + struct trie* next[10]; + int d; +}; + +typedef struct trie trie_t; +typedef struct kwset kwset_t; + +void f(kwset_t *kws, char const *p, char const *q) { + struct trie const *trie; + struct trie * const *next = kws->next; + register unsigned char c; + register char const *end = p; + register char const *lim = q; + register int d = 1; + register unsigned char const *y = kws->y; + + d = y[c = (end+=d)[-1]]; // no-warning + trie = next[c]; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7593875> When handling sizeof(VLA) it leads to a hole in +// the ExplodedGraph (causing a false positive) +//===----------------------------------------------------------------------===// + +int rdar_7593875_aux(int x); +int rdar_7593875(int n) { + int z[n > 10 ? 10 : n]; // VLA. + int v; + v = rdar_7593875_aux(sizeof(z)); + // Previously we got a false positive about 'v' being uninitialized. + return v; // no-warning +} + +//===----------------------------------------------------------------------===// +// Handle casts from symbolic regions (packaged as integers) to doubles. +// Previously this caused an assertion failure. +//===----------------------------------------------------------------------===// + +void *foo_rev95119(); +void baz_rev95119(double x); +void bar_rev95119() { + // foo_rev95119() returns a symbolic pointer. It is then + // cast to an int which is then cast to a double. + int value = (int) foo_rev95119(); + baz_rev95119((double)value); +} + +//===----------------------------------------------------------------------===// +// Handle loading a symbolic pointer from a symbolic region that was +// invalidated by a call to an unknown function. +//===----------------------------------------------------------------------===// + +void bar_rev95192(int **x); +void foo_rev95192(int **x) { + *x = 0; + bar_rev95192(x); + // Not a null dereference. + **x = 1; // no-warning +} + +//===----------------------------------------------------------------------===// +// Handle casts of a function to a function pointer with a different return +// value. We don't yet emit an error for such cases, but we now we at least +// don't crash when the return value gets interpreted in a way that +// violates our invariants. +//===----------------------------------------------------------------------===// + +void *foo_rev95267(); +int bar_rev95267() { + char (*Callback_rev95267)(void) = (char (*)(void)) foo_rev95267; + if ((*Callback_rev95267)() == (char) 0) + return 1; + return 0; +} + +// Same as previous case, but handle casts to 'void'. +int bar_rev95274() { + void (*Callback_rev95274)(void) = (void (*)(void)) foo_rev95267; + (*Callback_rev95274)(); + return 0; +} + +void rdar7582031_test_static_init_zero() { + static unsigned x; + if (x == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; +} +void rdar7582031_test_static_init_zero_b() { + static void* x; + if (x == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; +} + +//===----------------------------------------------------------------------===// +// Test handling of parameters that are structs that contain floats and // +// nested fields. // +//===----------------------------------------------------------------------===// + +struct s_rev95547_nested { float x, y; }; +struct s_rev95547 { + struct s_rev95547_nested z1; + struct s_rev95547_nested z2; +}; +float foo_rev95547(struct s_rev95547 w) { + return w.z1.x + 20.0; // no-warning +} +void foo_rev95547_b(struct s_rev95547 w) { + struct s_rev95547 w2 = w; + w2.z1.x += 20.0; // no-warning +} + +//===----------------------------------------------------------------------===// +// Test handling statement expressions that don't populate a CFG block that +// is used to represent the computation of the RHS of a logical operator. +// This previously triggered a crash. +//===----------------------------------------------------------------------===// + +void pr6938() { + if (1 && ({ + while (0); + 0; + }) == 0) { + } +} + +void pr6938_b() { + if (1 && *({ // expected-warning{{Dereference of null pointer}} + while (0) {} + ({ + (int *) 0; + }); + }) == 0) { + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7979430> - The CFG for code containing an empty +// @synchronized block was previously broken (and would crash the analyzer). +//===----------------------------------------------------------------------===// + +void r7979430(id x) { + @synchronized(x) {} +} + +//===----------------------------------------------------------------------=== +// PR 7361 - Test that functions wrapped in macro instantiations are analyzed. +//===----------------------------------------------------------------------=== +#define MAKE_TEST_FN() \ + void test_pr7361 (char a) {\ + char* b = 0x0; *b = a;\ + } + +MAKE_TEST_FN() // expected-warning{{null pointer}} + +//===----------------------------------------------------------------------=== +// PR 7491 - Test that symbolic expressions can be used as conditions. +//===----------------------------------------------------------------------=== + +void pr7491 () { + extern int getint(); + int a = getint()-1; + if (a) { + return; + } + if (!a) { + return; + } else { + // Should be unreachable + (void)*(char*)0; // no-warning + } +} + +//===----------------------------------------------------------------------=== +// PR 7475 - Test that assumptions about global variables are reset after +// calling a global function. +//===----------------------------------------------------------------------=== + +int *pr7475_someGlobal; +void pr7475_setUpGlobal(); + +void pr7475() { + if (pr7475_someGlobal == 0) + pr7475_setUpGlobal(); + *pr7475_someGlobal = 0; // no-warning +} + +void pr7475_warn() { + static int *someStatic = 0; + if (someStatic == 0) + pr7475_setUpGlobal(); + *someStatic = 0; // expected-warning{{null pointer}} +} + +// <rdar://problem/8202272> - __imag passed non-complex should not crash +float f0(_Complex float x) { + float l0 = __real x; + return __real l0 + __imag l0; +} + + +//===----------------------------------------------------------------------=== +// Test that we can reduce symbols to constants whether they are on the left +// or right side of an expression. +//===----------------------------------------------------------------------=== + +void reduce_to_constant(int x, int y) { + if (x != 20) + return; + + int a = x + y; + int b = y + x; + + if (y == -20 && a != 0) + (void)*(char*)0; // no-warning + if (y == -20 && b != 0) + (void)*(char*)0; // no-warning +} + +// <rdar://problem/8360854> - Test that code after a switch statement with no +// 'case:' labels is correctly evaluated. +void r8360854(int n) { + switch (n) { + default: ; + } + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{null pointer}} +} + +// PR 8050 - crash in CastSizeChecker when pointee is an incomplete type +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +void *malloc(size_t); + +struct PR8050; + +void pr8050(struct PR8050 **arg) +{ + *arg = malloc(1); +} + +// <rdar://problem/5880430> Switch on enum should not consider default case live +// if all enum values are covered +enum Cases { C1, C2, C3, C4 }; +void test_enum_cases(enum Cases C) { + switch (C) { + case C1: + case C2: + case C4: + case C3: + return; + } + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +void test_enum_cases_positive(enum Cases C) { + switch (C) { // expected-warning{{enumeration value 'C4' not handled in switch}} + case C1: + case C2: + case C3: + return; + } + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} +} + +// <rdar://problem/6351970> rule request: warn if synchronization mutex can be nil +void rdar6351970() { + id x = 0; + @synchronized(x) {} // expected-warning{{Nil value used as mutex for @synchronized() (no synchronization will occur)}} +} + +void rdar6351970_b(id x) { + if (!x) + @synchronized(x) {} // expected-warning{{Nil value used as mutex for @synchronized() (no synchronization will occur)}} +} + +void rdar6351970_c() { + id x; + @synchronized(x) {} // expected-warning{{Uninitialized value used as mutex for @synchronized}} +} + +@interface Rdar8578650 +- (id) foo8578650; +@end + +void rdar8578650(id x) { + @synchronized (x) { + [x foo8578650]; + } + // At this point we should assume that 'x' is not nil, not + // the inverse. + @synchronized (x) { // no-warning + } +} + +// <rdar://problem/6352035> rule request: direct structure member access null pointer dereference +@interface RDar6352035 { + int c; +} +- (void)foo; +- (void)bar; +@end + +@implementation RDar6352035 +- (void)foo { + RDar6352035 *friend = 0; + friend->c = 7; // expected-warning{{Instance variable access (via 'friend') results in a null pointer dereference}} +} +- (void)bar { + self = 0; + c = 7; // expected-warning{{Instance variable access (via 'self') results in a null pointer dereference}} +} +@end + +// PR 8149 - GNU statement expression in condition of ForStmt. +// This previously triggered an assertion failure in CFGBuilder. +void pr8149(void) { + for (; ({ do { } while (0); 0; });) { } +} + +// PR 8458 - Make sure @synchronized doesn't crash with properties. +@interface PR8458 {} +@property(readonly) id lock; +@end + +static +void __PR8458(PR8458 *x) { + @synchronized(x.lock) {} // no-warning +} + +// PR 8440 - False null dereference during store to array-in-field-in-global. +// This test case previously resulted in a bogus null deref warning from +// incorrect lazy symbolication logic in RegionStore. +static struct { + int num; + char **data; +} saved_pr8440; + +char *foo_pr8440(); +char **bar_pr8440(); +void baz_pr8440(int n) +{ + saved_pr8440.num = n; + if (saved_pr8440.data) + return; + saved_pr8440.data = bar_pr8440(); + for (int i = 0 ; i < n ; i ++) + saved_pr8440.data[i] = foo_pr8440(); // no-warning +} + +// Support direct accesses to non-null memory. Reported in: +// PR 5272 +// <rdar://problem/6839683> +int test_direct_address_load() { + int *p = (int*) 0x4000; + return *p; // no-warning +} + +void pr5272_test() { + struct pr5272 { int var2; }; + (*(struct pr5272*)0xBC000000).var2 = 0; // no-warning + (*(struct pr5272*)0xBC000000).var2 += 2; // no-warning +} + +// Support casting the return value of function to another different type +// This previously caused a crash, although we likely need more precise +// reasoning here. <rdar://problem/8663544> +void* rdar8663544(); +typedef struct {} Val8663544; +Val8663544 bazR8663544() { + Val8663544(*func) () = (Val8663544(*) ()) rdar8663544; + return func(); +} + +// PR 8619 - Handle ternary expressions with a call to a noreturn function. +// This previously resulted in a crash. +void pr8619_noreturn(int x) __attribute__((noreturn)); + +void pr8619(int a, int b, int c) { + a ?: pr8619_noreturn(b || c); +} + + +// PR 8646 - crash in the analyzer when handling unions. +union pr8648_union { + signed long long pr8648_union_field; +}; +void pr8648() { + long long y; + union pr8648_union x = { .pr8648_union_field = 0LL }; + y = x.pr8648_union_field; + + union pr8648_union z; + z = (union pr8648_union) { .pr8648_union_field = 0LL }; + + union pr8648_union w; + w = ({ (union pr8648_union) { .pr8648_union_field = 0LL }; }); + + // crash, no assignment + (void) ({ (union pr8648_union) { .pr8648_union_field = 0LL }; }).pr8648_union_field; + + // crash with assignment + y = ({ (union pr8648_union) { .pr8648_union_field = 0LL }; }).pr8648_union_field; +} + +// PR 9269 - don't assert when building the following CFG. The for statement +// contains a condition with multiple basic blocks, and the value of the +// statement expression is then indexed as part of a bigger condition expression. +// This example exposed a bug in child traversal in the CFGBuilder. +void pr9269() { + struct s { char *bar[10]; } baz[2] = { 0 }; + unsigned i = 0; + for (i = 0; + (* ({ while(0); ({ &baz[0]; }); })).bar[0] != 0; // expected-warning {{while loop has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}} + ++i) {} +} + +// Test evaluation of GNU-style ?:. +int pr9287(int type) { return type ? : 0; } // no-warning + +void pr9287_b(int type, int *p) { + int x = type ? : 0; + if (x) { + p = 0; + } + if (type) { + *p = 0xDEADBEEF; // expected-warning {{null pointer}} + } +} + +void pr9287_c(int type, int *p) { + int x = type ? : 0; + if (x) { + p = 0; + } + if (!type) { + *p = 0xDEADBEEF; // no-warning + } +} + +void test_switch() { + switch (4) { + case 1: { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + break; + } + case 4: { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} + break; + } + default: { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + break; + } + } +} + +// PR 9467. Tests various CFG optimizations. This previously crashed. +static void test(unsigned int bit_mask) +{ + unsigned int bit_index; + for (bit_index = 0; + bit_index < 24; + bit_index++) { + switch ((0x01 << bit_index) & bit_mask) { + case 0x100000: ; + } + } +} + +// Don't crash on code containing __label__. +int radar9414427_aux(); +void radar9414427() { + __label__ mylabel; + if (radar9414427_aux()) { + mylabel: do {} + while (0); + } +} + +// Analyze methods in @implementation (category) +@interface RDar9465344 +@end + +@implementation RDar9465344 (MyCategory) +- (void) testcategoryImpl { + int *p = 0x0; + *p = 0xDEADBEEF; // expected-warning {{null}} +} +@end + +@implementation RDar9465344 +@end + +// Don't crash when analyzing access to 'self' within a block. +@interface Rdar10380300Base +- (void) foo; +@end +@interface Rdar10380300 : Rdar10380300Base @end +@implementation Rdar10380300 +- (void)foo { + ^{ + [super foo]; + }(); +} +@end + diff --git a/clang/test/Analysis/new.cpp b/clang/test/Analysis/new.cpp new file mode 100644 index 0000000..5ca8c46 --- /dev/null +++ b/clang/test/Analysis/new.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s +// XFAIL: * + +void f1() { + int *n = new int; + if (*n) { // expected-warning {{Branch condition evaluates to a garbage value}} + } +} + +void f2() { + int *n = new int(3); + if (*n) { // no-warning + } +} + diff --git a/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m new file mode 100644 index 0000000..c1cc076 --- /dev/null +++ b/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -verify -Wno-objc-root-class %s + +// <rdar://problem/6888289> - This test case shows that a nil instance +// variable can possibly be initialized by a method. +@interface RDar6888289 +{ + id *x; +} +- (void) test:(id) y; +- (void) test2:(id) y; +- (void) invalidate; +@end + +id *getVal(void); + +@implementation RDar6888289 +- (void) test:(id)y { + if (!x) + [self invalidate]; + *x = y; +} +- (void) test2:(id)y { + if (!x) {} + *x = y; // expected-warning {{null}} +} + +- (void) invalidate { + x = getVal(); +} + +@end + diff --git a/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m new file mode 100644 index 0000000..e4d5aaf --- /dev/null +++ b/clang/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: %clang_cc1 -triple thumbv6-apple-ios4.0 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s + +@interface MyClass {} +- (void *)voidPtrM; +- (int)intM; +- (long long)longlongM; +- (unsigned long long)unsignedLongLongM; +- (double)doubleM; +- (long double)longDoubleM; +- (void)voidM; +@end +@implementation MyClass +- (void *)voidPtrM { return (void *)0; } +- (int)intM { return 0; } +- (long long)longlongM { return 0; } +- (unsigned long long)unsignedLongLongM { 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]; +} + +void createFoo3() { + MyClass *obj; + obj = 0; + + long long ll = [obj longlongM]; +} + +void createFoo4() { + MyClass *obj = 0; + + double d = [obj doubleM]; +} + +void createFoo5() { + MyClass *obj = (id)@""; + + double d = [obj doubleM]; // no-warning +} + +void createFoo6() { + MyClass *obj; + obj = 0; + + unsigned long long ull = [obj unsignedLongLongM]; +} + +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]; + } + + long long j = [obj longlongM]; +} + +int handleVoidInComma() { + MyClass *obj = 0; + return [obj voidM], 0; +} + +int marker(void) { // control reaches end of non-void function +} + +// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'unsignedLongLongM' is nil and returns a value of type 'unsigned long long' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage + +// CHECK-darwin9-NOT: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin9-NOT: warning: The receiver of message 'unsignedLongLongM' is nil and returns a value of type 'unsigned long long' that will be garbage +// CHECK-darwin9-NOT: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage +// CHECK-darwin9-NOT: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin9-NOT: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage +// CHECK-darwin9: 1 warning generated + diff --git a/clang/test/Analysis/no-exit-cfg.c b/clang/test/Analysis/no-exit-cfg.c new file mode 100644 index 0000000..1a80a25 --- /dev/null +++ b/clang/test/Analysis/no-exit-cfg.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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/clang/test/Analysis/no-outofbounds.c b/clang/test/Analysis/no-outofbounds.c new file mode 100644 index 0000000..821f486 --- /dev/null +++ b/clang/test/Analysis/no-outofbounds.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s + +//===----------------------------------------------------------------------===// +// This file tests cases where we should not flag out-of-bounds warnings. +//===----------------------------------------------------------------------===// + +void f() { + long x = 0; + char *y = (char*) &x; + char c = y[0] + y[1] + y[2]; // no-warning + short *z = (short*) &x; + short s = z[0] + z[1]; // no-warning +} + +void g() { + int a[2]; + char *b = (char*)a; + b[3] = 'c'; // no-warning +} + +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +void field() { + struct vec { size_t len; int data[0]; }; + // FIXME: Not warn for this. + struct vec *a = malloc(sizeof(struct vec) + 10); // expected-warning {{Cast a region whose size is not a multiple of the destination type size}} + a->len = 10; + a->data[1] = 5; // no-warning + free(a); +} diff --git a/clang/test/Analysis/null-deref-ps-region.c b/clang/test/Analysis/null-deref-ps-region.c new file mode 100644 index 0000000..08bfac7 --- /dev/null +++ b/clang/test/Analysis/null-deref-ps-region.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -std=gnu99 -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/clang/test/Analysis/null-deref-ps.c b/clang/test/Analysis/null-deref-ps.c new file mode 100644 index 0000000..a707970 --- /dev/null +++ b/clang/test/Analysis/null-deref-ps.c @@ -0,0 +1,313 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wno-error=return-type +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wno-error=return-type + +typedef unsigned uintptr_t; + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + __attribute__ ((__noreturn__)); + +#define assert(expr) \ + ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) + +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{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}} +} + +int f3(char* x) { + + int i = 2; + + if (x) + return x[i - 1]; + + return x[i+1]; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} +} + +int f3_b(char* x) { + + int i = 2; + + if (x) + return x[i - 1]; + + return x[i+1]++; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} +} + +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 (loaded from variable 'q')}} +} + +int f4_b() { + short array[2]; + uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}} + short *p = x; // expected-warning{{incompatible integer to pointer conversion}} + + // The following branch should be infeasible. + if (!(p == &array[0])) { // expected-warning{{Both operands to '==' always have the same value}} + 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}} + return 0; +} + +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 +} + +void f6d(int *p) { + bar(p, 0); + // At this point, 'p' cannot be null. + if (!p) { + int *q = 0; + *q = 0xDEADBEEF; // no-warning + } +} + +void f6e(int *p, int offset) { + // PR7406 - crash from treating an UnknownVal as defined, to see if it's 0. + bar((p+offset)+1, 0); // not crash +} + +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; +} + + +void 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 0; + *p = 10; + } + else p = 0; + + if (!x) + *p = 5; // no-warning + + return p; +} + +// Test case from <rdar://problem/6407949> +void f11(unsigned i) { + int *x = 0; + if (i >= 0) { // expected-warning{{always true}} + // 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; +} + +// PR 4759 - Attribute non-null checking by the analyzer was not correctly +// handling pointer values that were undefined. +void pr4759_aux(int *p) __attribute__((nonnull)); + +void pr4759() { + int *p; + pr4759_aux(p); // expected-warning{{Function call argument is an uninitialized value}} +} + +// Relax function call arguments invalidation to be aware of const +// arguments. Test with function pointers. radar://10595327 +void ttt(const int *nptr); +void ttt2(const int *nptr); +typedef void (*NoConstType)(int*); +int foo10595327(int b) { + void (*fp)(int *); + // We use path sensitivity to get the function declaration. Even when the + // function pointer is cast to non pointer-to-const parameter type, we can + // find the right function declaration. + if (b > 5) + fp = (NoConstType)ttt2; + else + fp = (NoConstType)ttt; + int x = 3; + int y = x + 1; + int *p = 0; + fp(&y); + if (x == y) + return *p; // no-warning + return 0; +} diff --git a/clang/test/Analysis/nullptr.cpp b/clang/test/Analysis/nullptr.cpp new file mode 100644 index 0000000..3119b4f --- /dev/null +++ b/clang/test/Analysis/nullptr.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -std=c++11 -Wno-conversion-null -analyze -analyzer-checker=core -analyzer-store region -verify %s + +// test to see if nullptr is detected as a null pointer +void foo1(void) { + char *np = nullptr; + *np = 0; // expected-warning{{Dereference of null pointer}} +} + +// check if comparing nullptr to nullptr is detected properly +void foo2(void) { + char *np1 = nullptr; + char *np2 = np1; + char c; + if (np1 == np2) + np1 = &c; + *np1 = 0; // no-warning +} + +// invoving a nullptr in a more complex operation should be cause a warning +void foo3(void) { + struct foo { + int a, f; + }; + char *np = nullptr; + // casting a nullptr to anything should be caught eventually + int *ip = &(((struct foo *)np)->f); + *ip = 0; // expected-warning{{Dereference of null pointer}} + // should be error here too, but analysis gets stopped +// *np = 0; +} + +// nullptr is implemented as a zero integer value, so should be able to compare +void foo4(void) { + char *np = nullptr; + if (np != 0) + *np = 0; // no-warning + char *cp = 0; + if (np != cp) + *np = 0; // no-warning +} + +int pr10372(void *& x) { + // GNU null is a pointer-sized integer, not a pointer. + x = __null; + // This used to crash. + return __null; +} + +void zoo1() { + char **p = 0; + delete *(p + 0); // expected-warning{{Dereference of null pointer}} +} + +void zoo2() { + int **a = 0; + int **b = 0; + asm ("nop" + :"=a"(*a) + :"0"(*b) // expected-warning{{Dereference of null pointer}} + ); +} + +int exprWithCleanups() { + struct S { + S(int a):a(a){} + ~S() {} + + int a; + }; + + int *x = 0; + return S(*x).a; // expected-warning{{Dereference of null pointer}} +} + +int materializeTempExpr() { + int *n = 0; + struct S { + int a; + S(int i): a(i) {} + }; + const S &s = S(*n); // expected-warning{{Dereference of null pointer}} + return s.a; +} diff --git a/clang/test/Analysis/objc-arc.m b/clang/test/Analysis/objc-arc.m new file mode 100644 index 0000000..e6c6ab5 --- /dev/null +++ b/clang/test/Analysis/objc-arc.m @@ -0,0 +1,220 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc %s + +typedef signed char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +typedef unsigned long NSUInteger; + +@protocol NSObject +- (BOOL)isEqual:(id)object; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSCoding; +@protocol NSMutableCopying; +@protocol NSFastEnumeration +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)alloc; +- (id)init; +- (NSString *)description; +@end +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (NSUInteger)count; +- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt; ++ (id)arrayWithObject:(id)anObject; ++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; ++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithArray:(NSArray *)array; +@end + +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +typedef double CFTimeInterval; +typedef CFTimeInterval CFAbsoluteTime; +extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); +typedef const struct __CFDate * CFDateRef; +extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); + +typedef const void* objc_objectptr_t; +__attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer); +__attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer); + +// Test the analyzer is working at all. +void test_working() { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{null}} +} + +// Test that in ARC mode that blocks are correctly automatically copied +// and not flagged as warnings by the analyzer. +typedef void (^Block)(void); +void testblock_bar(int x); + +Block testblock_foo(int x) { + Block b = ^{ testblock_bar(x); }; + return b; // no-warning +} + +Block testblock_baz(int x) { + return ^{ testblock_bar(x); }; // no-warning +} + +Block global_block; + +void testblock_qux(int x) { + global_block = ^{ testblock_bar(x); }; // no-warning +} + +// Test that Objective-C pointers are null initialized. +void test_nil_initialized() { + id x; + if (x == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +// Test that we don't flag leaks of Objective-C objects. +void test_alloc() { + [NSObject alloc]; // no-warning +} + +// Test that CF allocations are still caught as leaks. +void test_cf_leak() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} + (void) date; +} + +// Test that 'init' methods do not try to claim ownerhip of an *unowned* allocated object +// in ARC mode. +@interface RDar9424890_A : NSObject +- (id)initWithCleaner:(int)pop mop:(NSString *)mop ; +- (RDar9424890_A *)rdar9424890:(NSString *)identifier; +@end +@interface RDar9424890_B : NSObject +@end +@implementation RDar9424890_B +- (RDar9424890_A *)obj:(RDar9424890_A *)obj { + static NSString *WhizFiz = @"WhizFiz"; + RDar9424890_A *cell = [obj rdar9424890:WhizFiz]; + if (cell == ((void*)0)) { + cell = [[RDar9424890_A alloc] initWithCleaner:0 mop:WhizFiz]; // no-warning + } + return cell; +} +@end + +// Test that dead store checking works in the prescence of "cleanups" in the AST. +void rdar9424882() { + id x = [NSObject alloc]; // expected-warning {{Value stored to 'x' during its initialization is never read}} +} + +// Test +typedef const void *CFTypeRef; +typedef const struct __CFString *CFStringRef; + +@interface NSString +- (id) self; +@end + +CFTypeRef CFCreateSomething(); +CFStringRef CFCreateString(); +CFTypeRef CFGetSomething(); +CFStringRef CFGetString(); + +id CreateSomething(); +NSString *CreateNSString(); + +void from_cf() { + id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning{{never read}} + id obj2 = (__bridge_transfer NSString*)CFCreateString(); + [obj2 self]; // Add a use, to show we can use the object after it has been transfered. + id obj3 = (__bridge id)CFGetSomething(); + [obj3 self]; // Add a use, to show we can use the object after it has been bridged. + id obj4 = (__bridge NSString*)CFGetString(); // expected-warning{{never read}} + id obj5 = (__bridge id)CFCreateSomething(); // expected-warning{{never read}} expected-warning{{leak}} + id obj6 = (__bridge NSString*)CFCreateString(); // expected-warning{{never read}} expected-warning{{leak}} +} + +void to_cf(id obj) { + CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning{{never read}} + CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning{{never read}} + CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning{{never read}} + CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning{{never read}} +} + +void test_objc_retainedObject() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); + id x = objc_retainedObject(date); + (void) x; +} + +void test_objc_unretainedObject() { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} + id x = objc_unretainedObject(date); + (void) x; +} + +// Previously this resulted in a "return of stack address" warning. +id test_return() { + id x = (__bridge_transfer id) CFCreateString(); + return x; // no-warning +} + +void test_objc_arrays() { + { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY + NSObject *o = [[NSObject alloc] init]; + NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; + [a description]; + [o description]; + } + + { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY + NSObject *o = [[NSObject alloc] init]; + NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0]; + NSArray *a2 = [[NSArray alloc] initWithArray:a1]; + [a2 description]; + [o description]; + } + + { // CASE THREE -- OBJECT IN RETAINED @[] + NSObject *o = [[NSObject alloc] init]; + NSArray *a3 = @[o]; + [a3 description]; + [o description]; + } + { + // CASE 4, verify analyzer still working. + CFCreateString(); // expected-warning {{leak}} + } +} + +// <rdar://problem/11059275> - dispatch_set_context and ARC. +__attribute__((cf_returns_retained)) CFTypeRef CFBridgingRetain(id X); +typedef void* dispatch_object_t; +void dispatch_set_context(dispatch_object_t object, const void *context); + +void rdar11059275(dispatch_object_t object) { + NSObject *o = [[NSObject alloc] init]; + dispatch_set_context(object, CFBridgingRetain(o)); // no-warning +} +void rdar11059275_positive() { + NSObject *o = [[NSObject alloc] init]; // expected-warning {{leak}} + CFBridgingRetain(o); +} +void rdar11059275_negative() { + NSObject *o = [[NSObject alloc] init]; // no-warning + (void) o; +} + diff --git a/clang/test/Analysis/objc-bool.m b/clang/test/Analysis/objc-bool.m new file mode 100644 index 0000000..f95736a --- /dev/null +++ b/clang/test/Analysis/objc-bool.m @@ -0,0 +1,22 @@ +// RUN: %clang --analyze %s -o %t -Xclang -verify + +// Test handling of ObjC bool literals. + +typedef signed char BOOL; + +void rdar_10597458() { + if (__objc_yes) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +void rdar_10597458_b(BOOL b) { + if (b == __objc_no) + return; + + if (b == __objc_no) { + int *p = 0; + *p = 0xDEADBEEF; // no-warning + } +} diff --git a/clang/test/Analysis/objc-method-coverage.m b/clang/test/Analysis/objc-method-coverage.m new file mode 100644 index 0000000..056aafe --- /dev/null +++ b/clang/test/Analysis/objc-method-coverage.m @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-stats -fblocks %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=none -analyzer-stats -fblocks %s 2>&1 | FileCheck %s + +@interface I +int f() { + return 0; +} +@end + +@implementation I ++ (void *)ff{ + return (void*)0; +} +@end + +// CHECK: ... Statistics Collected ... +// CHECK: 2 AnalysisConsumer - The # of functions analysed (as top level).
\ No newline at end of file diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp new file mode 100644 index 0000000..73cd28a --- /dev/null +++ b/clang/test/Analysis/operator-calls.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s +struct X0 { }; +bool operator==(const X0&, const X0&); + +// PR7287 +struct test { int a[2]; }; + +void t2() { + test p = {{1,2}}; + test q; + q = p; +} + +bool PR7287(X0 a, X0 b) { + return operator==(a, b); +} diff --git a/clang/test/Analysis/out-of-bounds.c b/clang/test/Analysis/out-of-bounds.c new file mode 100644 index 0000000..a97bba5 --- /dev/null +++ b/clang/test/Analysis/out-of-bounds.c @@ -0,0 +1,154 @@ +// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.security.ArrayBoundV2 -verify %s + +// Tests doing an out-of-bounds access after the end of an array using: +// - constant integer index +// - constant integer size for buffer +void test1(int x) { + int buf[100]; + buf[100] = 1; // expected-warning{{Out of bound memory access}} +} + +void test1_ok(int x) { + int buf[100]; + buf[99] = 1; // no-warning +} + +const char test1_strings_underrun(int x) { + const char *mystr = "mary had a little lamb"; + return mystr[-1]; // expected-warning{{Out of bound memory access}} +} + +const char test1_strings_overrun(int x) { + const char *mystr = "mary had a little lamb"; + return mystr[1000]; // expected-warning{{Out of bound memory access}} +} + +const char test1_strings_ok(int x) { + const char *mystr = "mary had a little lamb"; + return mystr[5]; // no-warning +} + +// Tests doing an out-of-bounds access after the end of an array using: +// - indirect pointer to buffer +// - constant integer index +// - constant integer size for buffer +void test1_ptr(int x) { + int buf[100]; + int *p = buf; + p[101] = 1; // expected-warning{{Out of bound memory access}} +} + +void test1_ptr_ok(int x) { + int buf[100]; + int *p = buf; + p[99] = 1; // no-warning +} + +// Tests doing an out-of-bounds access before the start of an array using: +// - indirect pointer to buffer, manipulated using simple pointer arithmetic +// - constant integer index +// - constant integer size for buffer +void test1_ptr_arith(int x) { + int buf[100]; + int *p = buf; + p = p + 100; + p[0] = 1; // expected-warning{{Out of bound memory access}} +} + +void test1_ptr_arith_ok(int x) { + int buf[100]; + int *p = buf; + p = p + 99; + p[0] = 1; // no-warning +} + +void test1_ptr_arith_bad(int x) { + int buf[100]; + int *p = buf; + p = p + 99; + p[1] = 1; // expected-warning{{Out of bound memory access}} +} + +void test1_ptr_arith_ok2(int x) { + int buf[100]; + int *p = buf; + p = p + 99; + p[-1] = 1; // no-warning +} + +// Tests doing an out-of-bounds access before the start of an array using: +// - constant integer index +// - constant integer size for buffer +void test2(int x) { + int buf[100]; + buf[-1] = 1; // expected-warning{{Out of bound memory access}} +} + +// Tests doing an out-of-bounds access before the start of an array using: +// - indirect pointer to buffer +// - constant integer index +// - constant integer size for buffer +void test2_ptr(int x) { + int buf[100]; + int *p = buf; + p[-1] = 1; // expected-warning{{Out of bound memory access}} +} + +// Tests doing an out-of-bounds access before the start of an array using: +// - indirect pointer to buffer, manipulated using simple pointer arithmetic +// - constant integer index +// - constant integer size for buffer +void test2_ptr_arith(int x) { + int buf[100]; + int *p = buf; + --p; + p[0] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}} +} + +// Tests doing an out-of-bounds access before the start of a multi-dimensional +// array using: +// - constant integer indices +// - constant integer sizes for the array +void test2_multi(int x) { + int buf[100][100]; + buf[0][-1] = 1; // expected-warning{{Out of bound memory access}} +} + +// Tests doing an out-of-bounds access before the start of a multi-dimensional +// array using: +// - constant integer indices +// - constant integer sizes for the array +void test2_multi_b(int x) { + int buf[100][100]; + buf[-1][0] = 1; // expected-warning{{Out of bound memory access}} +} + +void test2_multi_ok(int x) { + int buf[100][100]; + buf[0][0] = 1; // no-warning +} + +// Testing if solver handles (symbol * constant) < constant +void test3(int x) { + int buf[100]; + if (x < 0) + buf[x] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}} +} + +// *** FIXME *** +// We don't get a warning here yet because our symbolic constraint solving +// doesn't handle: (symbol * constant) < constant +void test4(int x) { + int buf[100]; + if (x > 99) + buf[x] = 1; +} + +// Don't warn when indexing below the start of a symbolic region's whose +// base extent we don't know. +int *get_symbolic(); +void test_index_below_symboloc() { + int *buf = get_symbolic(); + buf[-1] = 0; // no-warning; +} + diff --git a/clang/test/Analysis/outofbound-notwork.c b/clang/test/Analysis/outofbound-notwork.c new file mode 100644 index 0000000..45e713b --- /dev/null +++ b/clang/test/Analysis/outofbound-notwork.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s +// XFAIL: * + +// Once we better handle modeling of sizes of VLAs, we can pull this back +// into outofbound.c. + +void sizeof_vla(int a) { + if (a == 5) { + char x[a]; + int y[sizeof(x)]; + y[4] = 4; // no-warning + y[5] = 5; // expected-warning{{out-of-bound}} + } +} + +void sizeof_vla_2(int a) { + if (a == 5) { + char x[a]; + int y[sizeof(x) / sizeof(char)]; + y[4] = 4; // no-warning + y[5] = 5; // expected-warning{{out-of-bound}} + } +} + +void sizeof_vla_3(int a) { + if (a == 5) { + char x[a]; + int y[sizeof(*&*&*&x)]; + y[4] = 4; // no-warning + y[5] = 5; // expected-warning{{out-of-bound}} + } +} diff --git a/clang/test/Analysis/outofbound.c b/clang/test/Analysis/outofbound.c new file mode 100644 index 0000000..2e7a7d3 --- /dev/null +++ b/clang/test/Analysis/outofbound.c @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void *calloc(size_t, size_t); + +char f1() { + char* s = "abcd"; + char c = s[4]; // no-warning + return s[5] + c; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} + +void f2() { + int *p = malloc(12); + p[3] = 4; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} + +struct three_words { + int c[3]; +}; + +struct seven_words { + int c[7]; +}; + +void f3() { + struct three_words a, *p; + p = &a; + p[0] = a; // no-warning + p[1] = a; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} + +void f4() { + struct seven_words c; + struct three_words a, *p = (struct three_words *)&c; + p[0] = a; // no-warning + p[1] = a; // no-warning + p[2] = a; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} + +void f5() { + char *p = calloc(2,2); + p[3] = '.'; // no-warning + p[4] = '!'; // expected-warning{{out-of-bound}} +} + +void f6() { + char a[2]; + int *b = (int*)a; + b[1] = 3; // expected-warning{{out-of-bound}} +} + +void f7() { + struct three_words a; + a.c[3] = 1; // expected-warning{{out-of-bound}} +} + +void vla(int a) { + if (a == 5) { + int x[a]; + x[4] = 4; // no-warning + x[5] = 5; // expected-warning{{out-of-bound}} + } +} + +void alloca_region(int a) { + if (a == 5) { + char *x = __builtin_alloca(a); + x[4] = 4; // no-warning + x[5] = 5; // expected-warning{{out-of-bound}} + } +} + +int symbolic_index(int a) { + int x[2] = {1, 2}; + if (a == 2) { + return x[a]; // expected-warning{{out-of-bound}} + } + return 0; +} + +int symbolic_index2(int a) { + int x[2] = {1, 2}; + if (a < 0) { + return x[a]; // expected-warning{{out-of-bound}} + } + return 0; +} diff --git a/clang/test/Analysis/override-werror.c b/clang/test/Analysis/override-werror.c new file mode 100644 index 0000000..d3b75f6 --- /dev/null +++ b/clang/test/Analysis/override-werror.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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}} +} + +void g(int *p) { + if (!p) *p = 0; // expected-warning{{null}} +} + diff --git a/clang/test/Analysis/plist-output-alternate.m b/clang/test/Analysis/plist-output-alternate.m new file mode 100644 index 0000000..83100dc --- /dev/null +++ b/clang/test/Analysis/plist-output-alternate.m @@ -0,0 +1,972 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o %t %s +// RUN: FileCheck --input-file %t %s + +void test_null_init(void) { + int *p = 0; + *p = 0xDEADBEEF; +} + +void test_null_assign(void) { + int *p; + p = 0; + *p = 0xDEADBEEF; +} + +void test_null_assign_transitive(void) { + int *p; + p = 0; + int *q = p; + *q = 0xDEADBEEF; +} + +void test_null_cond(int *p) { + if (!p) { + *p = 0xDEADBEEF; + } +} + +void test_null_cond_transitive(int *q) { + if (!q) { + int *p = q; + *p = 0xDEADBEEF; + } +} + +void test_null_field(void) { + struct s { int *p; } x; + x.p = 0; + *(x.p) = 0xDEADBEEF; +} + +// <rdar://problem/8331641> leak reports should not show paths that end with exit() (but ones that don't end with exit()) +void panic() __attribute__((noreturn)); +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 const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +typedef signed long CFIndex; +typedef CFIndex CFNumberType; +typedef const struct __CFNumber * CFNumberRef; + +extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); + +void rdar8331641(int x) { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}} + if (x) + panic(); + (void) value; +} + +// CHECK: <?xml version="1.0" encoding="UTF-8"?> +// CHECK: <plist version="1.0"> +// CHECK: <dict> +// CHECK: <key>files</key> +// CHECK: <array> +// CHECK: </array> +// CHECK: <key>diagnostics</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_init</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>16</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>16</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>30</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>30</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>30</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>30</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>36</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_field</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>38</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>53</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>82</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>82</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count</string> +// CHECK: <key>message</key> +// CHECK: <string>Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>23</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>82</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>55</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>58</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>58</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>58</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1</string> +// CHECK: <key>message</key> +// CHECK: <string>Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Potential leak of an object stored into 'value'</string> +// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string> +// CHECK: <key>type</key><string>Leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>rdar8331641</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>58</integer> +// CHECK: <key>col</key><integer>1</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </plist> diff --git a/clang/test/Analysis/plist-output.m b/clang/test/Analysis/plist-output.m new file mode 100644 index 0000000..72e8f8d --- /dev/null +++ b/clang/test/Analysis/plist-output.m @@ -0,0 +1,1339 @@ +// RUN: %clang --analyze %s -o %t > /dev/null 2>&1 +// RUN: FileCheck -input-file %t %s + +void test_null_init(void) { + int *p = 0; + *p = 0xDEADBEEF; +} + +void test_null_assign(void) { + int *p; + p = 0; + *p = 0xDEADBEEF; +} + +void test_null_assign_transitive(void) { + int *p; + p = 0; + int *q = p; + *q = 0xDEADBEEF; +} + +void test_null_cond(int *p) { + if (!p) { + *p = 0xDEADBEEF; + } +} + +void test_null_cond_transitive(int *q) { + if (!q) { + // FIXME: we need a diagnostic saying that p is initialized to 0 + int *p = q; + *p = 0xDEADBEEF; + } +} + +void test_null_field(void) { + struct s { int *p; } x; + x.p = 0; + *(x.p) = 0xDEADBEEF; +} + +void test_assumptions(int a, int b) +{ + if (a == 0) { + return; + } + if (b != 0) { + return; + } + int *p = 0; + *p = 0xDEADBEEF; +} + +int *bar_cond_assign(); +int test_cond_assign() { + int *p; + if (p = bar_cond_assign()) + return 1; + return *p; +} + +// The following previously crashed when generating extensive diagnostics. +// <rdar://problem/10797980> +@interface RDar10797980_help +@property (readonly) int x; +@end + +@interface RDar10797980 { + RDar10797980_help *y; +} +- (void) test; +@end + +@implementation RDar10797980 +- (void) test { + if (y.x == 1) { + int *p = 0; + *p = 0xDEADBEEF; // expected-warning {{deference}} + } +} +@end + +// CHECK: <?xml version="1.0" encoding="UTF-8"?> +// CHECK: <plist version="1.0"> +// CHECK: <dict> +// CHECK: <key>files</key> +// CHECK: <array> +// CHECK: </array> +// CHECK: <key>diagnostics</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>5</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_init</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>6</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>10</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>12</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>16</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>16</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'q')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>19</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>23</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>24</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>29</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>31</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>32</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>37</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_field</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>39</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>44</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>47</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>50</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>4</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_assumptions</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>51</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>56</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>56</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>57</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>11</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_cond_assign</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>59</integer> +// CHECK: <key>col</key><integer>10</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>path</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>76</integer> +// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>77</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>77</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>77</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>77</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>6</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> +// CHECK: <key>extended_message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>message</key> +// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> +// CHECK: <key>category</key><string>Logic error</string> +// CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>Objective-C method</string> +// CHECK: <key>issue_context</key><string>test</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>78</integer> +// CHECK: <key>col</key><integer>5</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </plist> + diff --git a/clang/test/Analysis/pr4209.m b/clang/test/Analysis/pr4209.m new file mode 100644 index 0000000..e16d1aa --- /dev/null +++ b/clang/test/Analysis/pr4209.m @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -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 <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 <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; +- (int)intValue; +@end @interface NSSimpleCString : NSString { +} +@end @interface NSConstantString : NSSimpleCString @end extern void *_NSConstantStringClassReference; +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; +@end typedef struct { +} +CMProfileLocation; +@interface NSResponder : NSObject <NSCoding> { +} +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@interface NSCell : NSObject <NSCopying, NSCoding> { +} +@end extern NSString *NSControlTintDidChangeNotification; +@interface NSActionCell : NSCell { +} +@end @class NSArray, NSDocument, NSWindow; +@interface NSWindowController : NSResponder <NSCoding> { +} +@end @class EBayCategoryType, GSEbayCategory, GBSearchRequest; +@interface GBCategoryChooserPanelController : NSWindowController { + GSEbayCategory *rootCategory; +} +- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; // expected-note {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}} +-(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}} expected-note {{using}} +@end @interface GSEbayCategory : NSObject <NSCoding> { +} +- (int) categoryID; // expected-note {{also found}} +- (GSEbayCategory *) parent; +- (GSEbayCategory*) subcategoryWithID:(int) inID; +@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}} + return 0; +} +- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories { + GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; // expected-warning {{multiple methods named 'categoryID' found}} + + 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) { + } + } + } +} +@end diff --git a/clang/test/Analysis/pr_2542_rdar_6793404.m b/clang/test/Analysis/pr_2542_rdar_6793404.m new file mode 100644 index 0000000..19c140d --- /dev/null +++ b/clang/test/Analysis/pr_2542_rdar_6793404.m @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %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 <NSObject> {} +- (id)init; ++ (id)alloc; +@end +typedef double NSTimeInterval; +enum { NSAnimationEaseInOut, NSAnimationEaseIn, NSAnimationEaseOut, NSAnimationLinear }; +typedef NSUInteger NSAnimationCurve; +@interface NSAnimation : NSObject <NSCopying, NSCoding> {} +- (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/clang/test/Analysis/pr_4164.c b/clang/test/Analysis/pr_4164.c new file mode 100644 index 0000000..187f4c6 --- /dev/null +++ b/clang/test/Analysis/pr_4164.c @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -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/clang/test/Analysis/properties.m b/clang/test/Analysis/properties.m new file mode 100644 index 0000000..4aa9180 --- /dev/null +++ b/clang/test/Analysis/properties.m @@ -0,0 +1,168 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -Wno-objc-root-class %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 +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@interface NSObject <NSObject> {} ++(id)alloc; +-(id)init; +-(id)autorelease; +-(id)copy; +-(id)retain; +@end +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; +-(id)initWithFormat:(NSString *)f,...; +-(BOOL)isEqualToString:(NSString *)s; ++ (id)string; +@end +@interface NSNumber : NSObject {} ++(id)alloc; +-(id)initWithInteger:(int)i; +@end + +// rdar://6946338 + +@interface Test1 : NSObject { + NSString *text; +} +-(id)myMethod; +@property (nonatomic, assign) NSString *text; +@end + + +@implementation Test1 + +@synthesize text; + +-(id)myMethod { + Test1 *cell = [[[Test1 alloc] init] autorelease]; + + NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}} + cell.text = string1; + + return cell; +} + +@end + + +// rdar://8824416 + +@interface MyNumber : NSObject +{ + NSNumber* _myNumber; +} + +- (id)initWithNumber:(NSNumber *)number; + +@property (nonatomic, readonly) NSNumber* myNumber; +@property (nonatomic, readonly) NSNumber* newMyNumber; + +@end + +@implementation MyNumber +@synthesize myNumber=_myNumber; + +- (id)initWithNumber:(NSNumber *)number +{ + self = [super init]; + + if ( self ) + { + _myNumber = [number copy]; + } + + return self; +} + +- (NSNumber*)newMyNumber +{ + if ( _myNumber ) + return [_myNumber retain]; + + return [[NSNumber alloc] initWithInteger:1]; +} + +- (id)valueForUndefinedKey:(NSString*)key +{ + id value = 0; + + if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"]) + value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained. + else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"]) + value = [self.myNumber retain]; // this line fixes the over release + else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"]) + value = self.newMyNumber; // this one is ok, since value is returned retained + else + value = [[NSNumber alloc] initWithInteger:0]; + + return [value autorelease]; // expected-warning {{Object sent -autorelease too many times}} +} + +@end + +NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber) +{ + NSNumber* result = aMyNumber.myNumber; + + return [result autorelease]; // expected-warning {{Object sent -autorelease too many times}} +} + + +// rdar://6611873 + +@interface Person : NSObject { + NSString *_name; +} +@property (retain) NSString * name; +@end + +@implementation Person +@synthesize name = _name; +@end + +void rdar6611873() { + Person *p = [[[Person alloc] init] autorelease]; + + p.name = [[NSString string] retain]; // expected-warning {{leak}} + p.name = [[NSString alloc] init]; // expected-warning {{leak}} +} + +@interface SubPerson : Person +-(NSString *)foo; +@end + +@implementation SubPerson +-(NSString *)foo { + return super.name; +} +@end + +// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses +@interface RDar9241180 +@property (readwrite,assign) id x; +-(id)testAnalyzer1:(int) y; +-(void)testAnalyzer2; +@end + +@implementation RDar9241180 +@synthesize x; +-(id)testAnalyzer1:(int)y { + RDar9241180 *o; + if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}} + return o; + return o; // expected-warning {{Undefined or garbage value returned to caller}} +} +-(void)testAnalyzer2 { + id y; + self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}} +} +@end + + diff --git a/clang/test/Analysis/pthreadlock.c b/clang/test/Analysis/pthreadlock.c new file mode 100644 index 0000000..4735d20 --- /dev/null +++ b/clang/test/Analysis/pthreadlock.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.PthreadLock -verify %s + +// Tests performing normal locking patterns and wrong locking orders + +typedef struct { + void *foo; +} pthread_mutex_t; + +typedef pthread_mutex_t lck_mtx_t; + +extern int pthread_mutex_lock(pthread_mutex_t *); +extern int pthread_mutex_unlock(pthread_mutex_t *); +extern int pthread_mutex_trylock(pthread_mutex_t *); +extern int lck_mtx_lock(lck_mtx_t *); +extern int lck_mtx_unlock(lck_mtx_t *); +extern int lck_mtx_try_lock(lck_mtx_t *); + +pthread_mutex_t mtx1, mtx2; +lck_mtx_t lck1, lck2; + +void +ok1(void) +{ + pthread_mutex_lock(&mtx1); // no-warning +} + +void +ok2(void) +{ + pthread_mutex_unlock(&mtx1); // no-warning +} + +void +ok3(void) +{ + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_unlock(&mtx1); // no-warning + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_unlock(&mtx1); // no-warning +} + +void +ok4(void) +{ + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_unlock(&mtx1); // no-warning + pthread_mutex_lock(&mtx2); // no-warning + pthread_mutex_unlock(&mtx2); // no-warning +} + +void +ok5(void) +{ + if (pthread_mutex_trylock(&mtx1) == 0) // no-warning + pthread_mutex_unlock(&mtx1); // no-warning +} + +void +ok6(void) +{ + lck_mtx_lock(&lck1); // no-warning +} + +void +ok7(void) +{ + if (lck_mtx_try_lock(&lck1) != 0) // no-warning + lck_mtx_unlock(&lck1); // no-warning +} + +void +bad1(void) +{ + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been acquired}} +} + +void +bad2(void) +{ + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_unlock(&mtx1); // no-warning + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been acquired}} +} + +void +bad3(void) +{ + pthread_mutex_lock(&mtx1); // no-warning + pthread_mutex_lock(&mtx2); // no-warning + pthread_mutex_unlock(&mtx1); // expected-warning{{This was not the most recently acquired lock}} + pthread_mutex_unlock(&mtx2); +} + +void +bad4(void) +{ + if (pthread_mutex_trylock(&mtx1)) // no-warning + return; + pthread_mutex_lock(&mtx2); // no-warning + pthread_mutex_unlock(&mtx1); // expected-warning{{This was not the most recently acquired lock}} +} + +void +bad5(void) +{ + lck_mtx_lock(&lck1); // no-warning + lck_mtx_lock(&lck1); // expected-warning{{This lock has already been acquired}} +} + +void +bad6(void) +{ + lck_mtx_lock(&lck1); // no-warning + lck_mtx_unlock(&lck1); // no-warning + lck_mtx_lock(&lck1); // no-warning + lck_mtx_lock(&lck1); // expected-warning{{This lock has already been acquired}} +} + +void +bad7(void) +{ + lck_mtx_lock(&lck1); // no-warning + lck_mtx_lock(&lck2); // no-warning + lck_mtx_unlock(&lck1); // expected-warning{{This was not the most recently acquired lock}} + lck_mtx_unlock(&lck2); +} + +void +bad8(void) +{ + if (lck_mtx_try_lock(&lck1) == 0) // no-warning + return; + lck_mtx_lock(&lck2); // no-warning + lck_mtx_unlock(&lck1); // expected-warning{{This was not the most recently acquired lock}} +} diff --git a/clang/test/Analysis/ptr-arith.c b/clang/test/Analysis/ptr-arith.c new file mode 100644 index 0000000..fb37f1c --- /dev/null +++ b/clang/test/Analysis/ptr-arith.c @@ -0,0 +1,288 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub -analyzer-store=region -verify -triple i686-apple-darwin9 %s + +// Used to trigger warnings for unreachable paths. +#define WARN do { int a, b; int c = &b-&a; } while (0) + +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'. +void* 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; +} + +void f3() { + int x, y; + int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point to the same memory chunk may cause incorrect result.}} + + int a[10]; + int *p = &a[2]; + int *q = &a[8]; + d = q-p; // no-warning +} + +void f4() { + int *p; + p = (int*) 0x10000; // expected-warning{{Using a fixed address is not portable because that address will probably not be valid in all environments or platforms.}} +} + +void f5() { + int x, y; + int *p; + p = &x + 1; // expected-warning{{Pointer arithmetic done on non-array variables means reliance on memory layout, which is dangerous.}} + + int a[10]; + p = a + 1; // no-warning +} + +// Allow arithmetic on different symbolic regions. +void f6(int *p, int *q) { + int d = q - p; // no-warning +} + +void null_operand(int *a) { +start: + // LHS is a label, RHS is NULL + if (&&start == 0) + WARN; // no-warning + if (&&start < 0) + WARN; // no-warning + if (&&start <= 0) + WARN; // no-warning + if (!(&&start != 0)) + WARN; // no-warning + if (!(&&start > 0)) + WARN; // no-warning + if (!(&&start >= 0)) + WARN; // no-warning + if (!(&&start - 0)) + WARN; // no-warning + + // LHS is a non-symbolic value, RHS is NULL + if (&a == 0) + WARN; // no-warning + if (&a < 0) + WARN; // no-warning + if (&a <= 0) + WARN; // no-warning + if (!(&a != 0)) + WARN; // no-warning + if (!(&a > 0)) + WARN; // no-warning + if (!(&a >= 0)) + WARN; // no-warning + + if (!(&a - 0)) // expected-warning{{Pointer arithmetic done on non-array variables}} + WARN; // no-warning + + // LHS is NULL, RHS is non-symbolic + // The same code is used for labels and non-symbolic values. + if (0 == &a) + WARN; // no-warning + if (0 > &a) + WARN; // no-warning + if (0 >= &a) + WARN; // no-warning + if (!(0 != &a)) + WARN; // no-warning + if (!(0 < &a)) + WARN; // no-warning + if (!(0 <= &a)) + WARN; // no-warning + + // LHS is a symbolic value, RHS is NULL + if (a == 0) + WARN; // expected-warning{{}} + if (a < 0) + WARN; // no-warning + if (a <= 0) + WARN; // expected-warning{{}} + if (!(a != 0)) + WARN; // expected-warning{{}} + if (!(a > 0)) + WARN; // expected-warning{{}} + if (!(a >= 0)) + WARN; // no-warning + if (!(a - 0)) + WARN; // expected-warning{{}} + + // LHS is NULL, RHS is a symbolic value + if (0 == a) + WARN; // expected-warning{{}} + if (0 > a) + WARN; // no-warning + if (0 >= a) + WARN; // expected-warning{{}} + if (!(0 != a)) + WARN; // expected-warning{{}} + if (!(0 < a)) + WARN; // expected-warning{{}} + if (!(0 <= a)) + WARN; // no-warning +} + +void const_locs() { + char *a = (char*)0x1000; + char *b = (char*)0x1100; +start: + if (a==b) + WARN; // no-warning + if (!(a!=b)) + WARN; // no-warning + if (a>b) + WARN; // no-warning + if (b<a) + WARN; // no-warning + if (a>=b) + WARN; // no-warning + if (b<=a) + WARN; // no-warning + if (b-a != 0x100) + WARN; // no-warning + + if (&&start == a) + WARN; // expected-warning{{}} + if (a == &&start) + WARN; // expected-warning{{}} + if (&a == (char**)a) + WARN; // expected-warning{{}} + if ((char**)a == &a) + WARN; // expected-warning{{}} +} + +void array_matching_types() { + int array[10]; + int *a = &array[2]; + int *b = &array[5]; + + if (a==b) + WARN; // no-warning + if (!(a!=b)) + WARN; // no-warning + if (a>b) + WARN; // no-warning + if (b<a) + WARN; // no-warning + if (a>=b) + WARN; // no-warning + if (b<=a) + WARN; // no-warning + if ((b-a) == 0) + WARN; // no-warning +} + +// This takes a different code path than array_matching_types() +void array_different_types() { + int array[10]; + int *a = &array[2]; + char *b = (char*)&array[5]; + + if (a==b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (!(a!=b)) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (a>b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (b<a) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (a>=b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (b<=a) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning +} + +struct test { int x; int y; }; +void struct_fields() { + struct test a, b; + + if (&a.x == &a.y) + WARN; // no-warning + if (!(&a.x != &a.y)) + WARN; // no-warning + if (&a.x > &a.y) + WARN; // no-warning + if (&a.y < &a.x) + WARN; // no-warning + if (&a.x >= &a.y) + WARN; // no-warning + if (&a.y <= &a.x) + WARN; // no-warning + + if (&a.x == &b.x) + WARN; // no-warning + if (!(&a.x != &b.x)) + WARN; // no-warning + if (&a.x > &b.x) + WARN; // expected-warning{{}} + if (&b.x < &a.x) + WARN; // expected-warning{{}} + if (&a.x >= &b.x) + WARN; // expected-warning{{}} + if (&b.x <= &a.x) + WARN; // expected-warning{{}} +} + +void mixed_region_types() { + struct test s; + int array[2]; + void *a = &array, *b = &s; + + if (&a == &b) + WARN; // no-warning + if (!(&a != &b)) + WARN; // no-warning + if (&a > &b) + WARN; // expected-warning{{}} + if (&b < &a) + WARN; // expected-warning{{}} + if (&a >= &b) + WARN; // expected-warning{{}} + if (&b <= &a) + WARN; // expected-warning{{}} +} + +void symbolic_region(int *p) { + int a; + + if (&a == p) + WARN; // no-warning + if (&a != p) + WARN; // expected-warning{{}} + if (&a > p) + WARN; // expected-warning{{}} + if (&a < p) + WARN; // expected-warning{{}} + if (&a >= p) + WARN; // expected-warning{{}} + if (&a <= p) + WARN; // expected-warning{{}} +} + +void PR7527 (int *p) { + if (((int) p) & 1) // not crash + return; +} diff --git a/clang/test/Analysis/rdar-6442306-1.m b/clang/test/Analysis/rdar-6442306-1.m new file mode 100644 index 0000000..62992d0 --- /dev/null +++ b/clang/test/Analysis/rdar-6442306-1.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %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[0]; +} __Request__SetPortalSize_t; + +double __Foo_READSWAP__double(double*); + +static __inline__ bar_return_t +__Beeble_check__Request__SetPortalSize_t(__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); + } + return 0; +} diff --git a/clang/test/Analysis/rdar-6540084.m b/clang/test/Analysis/rdar-6540084.m new file mode 100644 index 0000000..d710c47 --- /dev/null +++ b/clang/test/Analysis/rdar-6540084.m @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores -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 <NSObject> {} @end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@class NSArray; +@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; // expected-note{{forward declaration of class here}} +@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; + } + } + } + while (1) {} +} +@end diff --git a/clang/test/Analysis/rdar-6541136-region.c b/clang/test/Analysis/rdar-6541136-region.c new file mode 100644 index 0000000..b90d4f4 --- /dev/null +++ b/clang/test/Analysis/rdar-6541136-region.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,experimental.security.ArrayBound -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 test1( void ) { + kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese; + struct load_wine *cmd = (void*) &wonky[1]; + cmd = cmd; + char *p = (void*) &wonky[1]; + kernel_tea_cheese_t *q = &wonky[1]; + // This test case tests both the RegionStore logic (doesn't crash) and + // the out-of-bounds checking. We don't expect the warning for now since + // out-of-bound checking is temporarily disabled. + kernel_tea_cheese_t r = *q; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} + +void test1_b( 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; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} diff --git a/clang/test/Analysis/rdar-6562655.m b/clang/test/Analysis/rdar-6562655.m new file mode 100644 index 0000000..3a59273 --- /dev/null +++ b/clang/test/Analysis/rdar-6562655.m @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=basic -analyzer-store=region -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 <NSObject> {} +@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSResponder : NSObject <NSCoding> {} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end enum { +NSNullCellType = 0, NSTextCellType = 1, NSImageCellType = 2 }; +typedef struct __CFlags { + unsigned int botnet:3; +} + _CFlags; +@interface Bar : NSObject <NSCopying, NSCoding> { + _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 { return 0; } +- (void)encodeWithCoder:(NSCoder *)coder {} +@end +@implementation Bar (BarBotnet) +- (NSBotnet)botnet { + if (!(*(BarAuxiliary **)&self->_support)->auxCFlags.botnetIsSet) { + _cFlags.botnet = [self _initialBotnetZorg]; + } + while (1) {} +} +@end diff --git a/clang/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/clang/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m new file mode 100644 index 0000000..5af4776 --- /dev/null +++ b/clang/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify -Wno-objc-root-class %s + +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]; // no-warning +} + +void createFoo2() { + MyClass *obj = 0; + [obj foo]; // no-warning + Bar f = [obj foo]; // no-warning +} + diff --git a/clang/test/Analysis/rdar-7168531.m b/clang/test/Analysis/rdar-7168531.m new file mode 100644 index 0000000..1516255 --- /dev/null +++ b/clang/test/Analysis/rdar-7168531.m @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -triple i386-apple-darwin10 -fobjc-fragile-abi -analyzer-store=region %s + +// Note that the target triple is important for this test case. It specifies that we use the +// fragile Objective-C ABI. + +@interface Foo { + int x; +} +@end + +@implementation Foo +static Foo* bar(Foo *p) { + if (p->x) + return ++p; // This is only valid for the fragile ABI. + + return p; +} +@end diff --git a/clang/test/Analysis/redefined_system.c b/clang/test/Analysis/redefined_system.c new file mode 100644 index 0000000..3c08b5e --- /dev/null +++ b/clang/test/Analysis/redefined_system.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=unix,core,experimental.security.taint -w -verify %s + +// Make sure we don't crash when someone redefines a system function we reason about. + +char memmove (); +char malloc(); +char system(); +char stdin(); +char memccpy(); +char free(); +char strdup(); +char atoi(); + +int foo () { + return memmove() + malloc() + system() + stdin() + memccpy() + free() + strdup() + atoi(); + +} diff --git a/clang/test/Analysis/refcnt_naming.m b/clang/test/Analysis/refcnt_naming.m new file mode 100644 index 0000000..aff713b --- /dev/null +++ b/clang/test/Analysis/refcnt_naming.m @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -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 <NSObject> {} @end +@class NSArray, NSString, NSURL; + +@interface NamingTest : NSObject {} +-(NSObject*)copyPhoto; +-(NSObject*)mutableCopyPhoto; +-(NSObject*)mutable; +-(NSObject*)mutableCopying; +-(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_theprefixdoescount; // read as "new theprefixdoescount" +-(NSObject*)newestAwesomeStuff; // read as "newest awesome stuff" + +@end + +@interface MyClass : NSObject +{ + id myObject; +} +- (NSURL *)myMethod:(NSString *)inString; +- (NSURL *)getMethod:(NSString*)inString; +- (NSURL *)getMethod2:(NSString*)inString; +- (void)addObject:(id) __attribute__((ns_consumed)) X; +- (void)addObject2:(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 +} + +- (NSURL *)getMethod2:(NSString *)inString +{ + NSURL *url = (NSURL *)CFURLCreateWithString(0, (CFStringRef)inString, 0); // expected-warning{{leak}} + [self addObject2:url]; + return url; +} + +void testNames(NamingTest* x) { + [x copyPhoto]; // expected-warning{{leak}} + [x mutableCopyPhoto]; // expected-warning{{leak}} + [x mutable]; // no-warning + [x mutableCopying]; // no-warning + [x photocopy]; // no-warning + [x photoCopy]; // no-warning + [x __blebPRCopy]; // no-warning + [x __blebPRcopy]; // no-warning + [x new_theprefixdoescount]; // expected-warning{{leak}} + [x newestAwesomeStuff]; // no-warning +} + + +- (void)addObject:(id)X +{ + myObject = X; +} + +- (void)addObject2:(id)X +{ + myObject = X; +} + +@end + diff --git a/clang/test/Analysis/reference.cpp b/clang/test/Analysis/reference.cpp new file mode 100644 index 0000000..5897e68 --- /dev/null +++ b/clang/test/Analysis/reference.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s +// XFAIL + +typedef typeof(sizeof(int)) size_t; +void malloc (size_t); + +void f1() { + int const &i = 3; // <--- **FIXME** This is currently not being modeled correctly. + int b = i; + + int *p = 0; + + if (b != 3) + *p = 1; // no-warning +} + +char* ptr(); +char& ref(); + +// These next two tests just shouldn't crash. +char t1 () { + ref() = 'c'; + return '0'; +} + +// just a sanity test, the same behavior as t1() +char t2 () { + *ptr() = 'c'; + return '0'; +} + +// Each of the tests below is repeated with pointers as well as references. +// This is mostly a sanity check, but then again, both should work! +char t3 () { + char& r = ref(); + r = 'c'; // no-warning + if (r) return r; + return *(char*)0; // no-warning +} + +char t4 () { + char* p = ptr(); + *p = 'c'; // no-warning + if (*p) return *p; + return *(char*)0; // no-warning +} + +char t5 (char& r) { + r = 'c'; // no-warning + if (r) return r; + return *(char*)0; // no-warning +} + +char t6 (char* p) { + *p = 'c'; // no-warning + if (*p) return *p; + return *(char*)0; // no-warning +} diff --git a/clang/test/Analysis/region-1.m b/clang/test/Analysis/region-1.m new file mode 100644 index 0000000..be92766 --- /dev/null +++ b/clang/test/Analysis/region-1.m @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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 <NSObject> { +} +@end @class NSArray; +@interface NSResponder : NSObject <NSCoding> { +} +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@class JabasectItem; +@protocol EcoClassifier; +@protocol EcoClassInterfaceCommons <EcoClassifier> @end @protocol EcoImplementation; +@protocol EcoBehavioredClassifier <EcoClassInterfaceCommons> - (NSArray *) implementations; +@end enum { +CK_UNRESTRICTED= 0, CK_READ_ONLY, CK_ADD_ONLY, CK_REMOVE_ONLY }; +@protocol EcoClass <EcoBehavioredClassifier> - (NSArray *) ownedAttributes; +@end @protocol EcoNamespace; +@protocol EcoType; +@protocol EcoClassifier <EcoNamespace,EcoType> - (NSArray *) features; +@end @protocol EcoComment; +@protocol EcoElement <NSObject> - (NSArray *) ownedElements; +@end @protocol EcoDirectedRelationship; +@protocol EcoNamedElement <EcoElement> - (NSString *) name; +@end extern NSString *const JabaPathSeparator; +@protocol EcoNamespace <EcoNamedElement> - (NSArray *) Legs; +@end enum { +PDK_IN=0, PDK_INOUT, PDK_OUT, PDK_RETURN }; +@interface EcoElementImp : NSObject <EcoElement, NSCoding> { +} +@end @class EcoNamespace; +@interface EcoNamedElementImp : EcoElementImp <EcoNamedElement>{ +} +@end @interface EcoNamespaceImp : EcoNamedElementImp <EcoNamespace> { +} +@end @class JabaSCDocController, JabaSCDisplaySpecification; +@interface JabaSCSharedDiagramViewController : NSObject { +} +@end extern NSString *const JabaSCsectGraphicNamesectIdentifier; +@interface EcoClassifierImp : EcoNamespaceImp <EcoClassifier> { +} +@end @class EcoOperationImp; +@interface EcoClassImp : EcoClassifierImp <EcoClass> { +} +@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 <EcoClassInterfaceCommons> - (JabaSourceLanguage)language; +@end @interface JabaSCClass : EcoClassImp <JabaSCClassifier> { +} +@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 { + return 0; +} +- (void)revealSourceInEditor:(JabasectItem *)sectItem duperGesture:(BOOL)duperGesture { + id <EcoNamedElement> selectedElement = [sectItem representedObject]; + id <EcoNamedElement> selectedClassifier = selectedElement; + DosSymbol *symbol=((void *)0); + if([selectedClassifier isLegOfClass:[JabaSCClass class]]) { + symbol = [HancodeFett symbolFromClass:(JabaSCClass *) selectedClassifier]; + } +} +@end diff --git a/clang/test/Analysis/retain-release-gc-only.m b/clang/test/Analysis/retain-release-gc-only.m new file mode 100644 index 0000000..0340a3c --- /dev/null +++ b/clang/test/Analysis/retain-release-gc-only.m @@ -0,0 +1,387 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify -Wno-objc-root-class %s + +//===----------------------------------------------------------------------===// +// Header stuff. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long uintptr_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned int UInt32; +typedef signed long CFIndex; +typedef struct { + CFIndex location; + CFIndex length; +} CFRange; +static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) { + CFRange range; + range.location = loc; + range.length = len; + return range; +} +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 struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +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 int kern_return_t; +typedef kern_return_t mach_error_t; +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 const struct __CFAttributedString *CFAttributedStringRef; +typedef struct __CFAttributedString *CFMutableAttributedStringRef; +extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ; +extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ; +extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +- (id)autorelease; +- (Class)class; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +- (oneway void)release; +- (id)copy; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString, NSDictionary; +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +- (id)init; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @class NSString, NSURL, NSError; +@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary; +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (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; +@end typedef double CGFloat; +struct CGSize { +}; +typedef struct CGSize CGSize; +struct CGRect { +}; +typedef struct CGRect CGRect; +typedef mach_port_t io_object_t; +typedef char io_name_t[128]; +typedef io_object_t io_iterator_t; +typedef io_object_t io_service_t; +typedef struct IONotificationPort * IONotificationPortRef; +typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); +io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); +kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); +kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); +kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); +CFMutableDictionaryRef IOServiceMatching( const char * name ); +CFMutableDictionaryRef IOServiceNameMatching( const char * name ); +CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); +CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); +CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ); +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 NSTask : NSObject - (id)init; +@end typedef struct CGColorSpace *CGColorSpaceRef; +typedef struct CGImage *CGImageRef; +typedef struct CGLayer *CGLayerRef; +@interface NSResponder : NSObject <NSCoding> { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end @protocol NSValidatedUserInterfaceItem - (SEL)action; +@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem; +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +@interface NSApplication : NSResponder <NSUserInterfaceValidations> { +} +@end enum { +NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 }; +typedef NSUInteger NSApplicationTerminateReply; +@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView; +@interface NSCell : NSObject <NSCopying, NSCoding> { +} +@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError; +typedef struct { +} +CVTimeStamp; +@interface CIImage : NSObject <NSCoding, NSCopying> { +} +typedef int CIFormat; +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&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; +- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d; +@end extern NSString* const QCRendererEventKey; +@protocol QCCompositionRenderer - (NSDictionary*) attributes; +@end @interface QCRenderer : NSObject <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end extern NSString* const QCViewDidStartRenderingNotification; +@interface QCView : NSView <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end enum { +ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, }; +@class ICDevice; +@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device; +@end extern NSString *const ICScannerStatusWarmingUp; +@class ICScannerDevice; +@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner; +@end +CFTypeRef CFMakeCollectable(CFTypeRef cf) ; + +static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef +cf) { + return cf ? (id)CFMakeCollectable(cf) : ((void*)0); +} + +//===----------------------------------------------------------------------===// +// 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); +} + +void f3b() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning + CFMakeCollectable(A); +} + + +void f4() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}} + NSMakeCollectable(A); + CFRetain(A); +} + +void f4b() { + CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning + NSMakeCollectable(A); +} + +void f5() { + id x = [NSMakeCollectable(CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks)) autorelease]; // no-warning +} + +void f5b() { + id x = [(id) CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks) autorelease]; // expected-warning{{leak}} +} + +// 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}} + CFRetain(s); + return s; +} +- (CFMutableArrayRef)newArray{ + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/6948053> False positive: object substitution during -init* +// methods warns about returning +0 when using -fobjc-gc-only +//===----------------------------------------------------------------------===// + +@interface MyClassRdar6948053 : NSObject +- (id) init; ++ (id) shared; +@end + +@implementation MyClassRdar6948053 ++(id) shared { + return (id) 0; +} +- (id) init +{ + Class myClass = [self class]; + [self release]; + return [[myClass shared] retain]; // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/7174400> 'ciContext createCGImage:outputImage fromRect:' returns a retained CF object (not GC'ed)//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// + +void rdar_7174400(QCView *view, QCRenderer *renderer, CIContext *context, + NSString *str, CIImage *img, CGRect rect, + CIFormat form, CGColorSpaceRef cs) { + [view createSnapshotImageOfType:str]; // no-warning + [renderer createSnapshotImageOfType:str]; // no-warning + [context createCGImage:img fromRect:rect]; // expected-warning{{leak}} + [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6250216> Warn against using -[NSAutoreleasePool release] in +// GC mode +//===----------------------------------------------------------------------===// + +void rdar_6250216(void) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + [pool release]; // expected-warning{{Use -drain instead of -release when using NSAutoreleasePool and garbage collection}} +} + + +//===----------------------------------------------------------------------===// +// <rdar://problem/7407273> Don't crash when analyzing messages sent to blocks +//===----------------------------------------------------------------------===// + +@class RDar7407273; +typedef void (^RDar7407273Block)(RDar7407273 *operation); +void rdar7407273(RDar7407273Block b) { + [b copy]; +} + +//===----------------------------------------------------------------------===// +// 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}} +} + +@interface MyClassTestCFAttr : NSObject {} +- (NSDate*) returnsCFRetained __attribute__((cf_returns_retained)); +- (NSDate*) alsoReturnsRetained; +- (NSDate*) returnsNSRetained __attribute__((ns_returns_retained)); +@end + +__attribute__((cf_returns_retained)) +CFDateRef returnsRetainedCFDate() { + return CFDateCreate(0, CFAbsoluteTimeGetCurrent()); +} + +@implementation MyClassTestCFAttr +- (NSDate*) returnsCFRetained { + return (NSDate*) returnsRetainedCFDate(); // No leak. +} + +- (NSDate*) alsoReturnsRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} + +- (NSDate*) returnsNSRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} +@end diff --git a/clang/test/Analysis/retain-release-inline.m b/clang/test/Analysis/retain-release-inline.m new file mode 100644 index 0000000..610df7f --- /dev/null +++ b/clang/test/Analysis/retain-release-inline.m @@ -0,0 +1,347 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -analyzer-ipa=inlining -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +// +// #include <Cocoa/Cocoa.h> +// #include <CoreFoundation/CoreFoundation.h> +// #include <DiskArbitration/DiskArbitration.h> +// #include <QuartzCore/QuartzCore.h> +// #include <Quartz/Quartz.h> +// #include <IOKit/IOKitLib.h> +// +// It includes the basic definitions for the test cases below. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long uintptr_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned int UInt32; +typedef signed long CFIndex; +typedef CFIndex CFByteOrder; +typedef struct { + CFIndex location; + CFIndex length; +} CFRange; +static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) { + CFRange range; + range.location = loc; + range.length = len; + return range; +} +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 struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +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 int kern_return_t; +typedef kern_return_t mach_error_t; +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 const struct __CFAttributedString *CFAttributedStringRef; +typedef struct __CFAttributedString *CFMutableAttributedStringRef; +extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ; +extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ; +extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +- (id)autorelease; +- (id)init; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString, NSDictionary; +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; +- (NSString *)stringByAppendingString:(NSString *)aString; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @class NSString, NSURL, NSError; +@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary; +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (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; +@end typedef double CGFloat; +struct CGSize { +}; +typedef struct CGSize CGSize; +struct CGRect { +}; +typedef struct CGRect CGRect; +typedef mach_port_t io_object_t; +typedef char io_name_t[128]; +typedef io_object_t io_iterator_t; +typedef io_object_t io_service_t; +typedef struct IONotificationPort * IONotificationPortRef; +typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); +io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); +kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); +kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); +kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); +CFMutableDictionaryRef IOServiceMatching( const char * name ); +CFMutableDictionaryRef IOServiceNameMatching( const char * name ); +CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); +CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); +CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ); +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 NSTask : NSObject - (id)init; +@end typedef struct CGColorSpace *CGColorSpaceRef; +typedef struct CGImage *CGImageRef; +typedef struct CGLayer *CGLayerRef; +@interface NSResponder : NSObject <NSCoding> { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end @protocol NSValidatedUserInterfaceItem - (SEL)action; +@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem; +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +@interface NSApplication : NSResponder <NSUserInterfaceValidations> { +} +@end enum { +NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 }; +typedef NSUInteger NSApplicationTerminateReply; +@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView; +@interface NSCell : NSObject <NSCopying, NSCoding> { +} +@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError; +typedef struct { +} +CVTimeStamp; +@interface CIImage : NSObject <NSCoding, NSCopying> { +} +typedef int CIFormat; +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&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; +- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d; +@end extern NSString* const QCRendererEventKey; +@protocol QCCompositionRenderer - (NSDictionary*) attributes; +@end @interface QCRenderer : NSObject <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end extern NSString* const QCViewDidStartRenderingNotification; +@interface QCView : NSView <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end enum { +ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, }; +@class ICDevice; +@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device; +@end extern NSString *const ICScannerStatusWarmingUp; +@class ICScannerDevice; +@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner; +@end + +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +typedef unsigned long CFTypeID; +struct CGPoint { + CGFloat x; + CGFloat y; +}; +typedef struct CGPoint CGPoint; +typedef struct CGGradient *CGGradientRef; +typedef uint32_t CGGradientDrawingOptions; +extern CFTypeID CGGradientGetTypeID(void); +extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef + space, const CGFloat components[], const CGFloat locations[], size_t count); +extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space, + CFArrayRef colors, const CGFloat locations[]); +extern CGGradientRef CGGradientRetain(CGGradientRef gradient); +extern void CGGradientRelease(CGGradientRef gradient); +typedef struct CGContext *CGContextRef; +extern void CGContextDrawLinearGradient(CGContextRef context, + CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, + CGGradientDrawingOptions options); +extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); + +@interface NSMutableArray : NSObject +- (void)addObject:(id)object; ++ (id)array; +@end + +enum { + NSASCIIStringEncoding = 1, + NSNEXTSTEPStringEncoding = 2, + NSJapaneseEUCStringEncoding = 3, + NSUTF8StringEncoding = 4, + NSISOLatin1StringEncoding = 5, + NSSymbolStringEncoding = 6, + NSNonLossyASCIIStringEncoding = 7, +}; +typedef struct __CFString * CFMutableStringRef; +typedef NSUInteger NSStringEncoding; + +extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +void foo(id x) { + [x retain]; +} + +void bar(id x) { + [x release]; +} + +void test() { + NSString *s = [[NSString alloc] init]; // expected-warning {{Potential leak}} + foo(s); + foo(s); + bar(s); +} +void test_neg() { + NSString *s = [[NSString alloc] init]; // no-warning + foo(s); + foo(s); + bar(s); + bar(s); + bar(s); +} + +//===----------------------------------------------------------------------===// +// Test returning retained and not-retained values. +//===----------------------------------------------------------------------===// + +// On return (intraprocedural), assume CF objects are leaked. +CFStringRef test_return_ratained_CF(char *bytes) { + CFStringRef str; + return CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}} +} + +// On return (intraprocedural), assume NSObjects are not leaked. +id test_return_retained_NS() { + return [[NSString alloc] init]; // no-warning +} + +void test_test_return_retained() { + id x = test_return_retained_NS(); // expected-warning {{leak}} + [x retain]; + [x release]; +} + +//===----------------------------------------------------------------------===// +// Test not applying "double effects" from inlining and RetainCountChecker summaries. +// If we inline a call, we should already see its retain/release semantics. +//===----------------------------------------------------------------------===// + +__attribute__((cf_returns_retained)) CFStringRef test_return_inline(CFStringRef x) { + CFRetain(x); + return x; +} + +void test_test_return_inline(char *bytes) { + CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); + // After this call, 'str' really has +2 reference count. + CFStringRef str2 = test_return_inline(str); + // After this call, 'str' really has a +1 reference count. + CFRelease(str); + // After this call, 'str2' and 'str' has a +0 reference count. + CFRelease(str2); +} + +void test_test_return_inline_2(char *bytes) { + CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}} + // After this call, 'str' really has +2 reference count. + CFStringRef str2 = test_return_inline(str); + // After this call, 'str' really has a +1 reference count. + CFRelease(str); +} + + + diff --git a/clang/test/Analysis/retain-release-path-notes-gc.m b/clang/test/Analysis/retain-release-path-notes-gc.m new file mode 100644 index 0000000..1e74f00 --- /dev/null +++ b/clang/test/Analysis/retain-release-path-notes-gc.m @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s + +/*** +This file is for testing the path-sensitive notes for retain/release errors. +Its goal is to have simple branch coverage of any path-based diagnostics, +not to actually check all possible retain/release errors. + +This file is for notes that only appear in a GC-enabled analysis. +Non-specific and ref-count-only notes should go in retain-release-path-notes.m. +***/ + +@interface NSObject ++ (id)alloc; +- (id)init; +- (void)dealloc; + +- (Class)class; + +- (id)retain; +- (void)release; +- (void)autorelease; +@end + +@interface Foo : NSObject +- (id)methodWithValue; +@property(retain) id propertyValue; +@end + +typedef struct CFType *CFTypeRef; +CFTypeRef CFRetain(CFTypeRef); +void CFRelease(CFTypeRef); + +id NSMakeCollectable(CFTypeRef); +CFTypeRef CFMakeCollectable(CFTypeRef); + +CFTypeRef CFCreateSomething(); +CFTypeRef CFGetSomething(); + + +void creationViaCFCreate () { + CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void makeCollectable () { + CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +2 retain count}} + CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1}} + NSMakeCollectable(leaked); // expected-note{{In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector}} + CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void retainReleaseIgnored () { + id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +0 retain count}} + [object retain]; // expected-note{{In GC mode the 'retain' message has no effect}} + [object release]; // expected-note{{In GC mode the 'release' message has no effect}} + [object autorelease]; // expected-note{{In GC mode an 'autorelease' has no effect}} + CFRelease((CFTypeRef)object); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} +} + +@implementation Foo (FundamentalRuleUnderGC) +- (id)getViolation { + id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} +} + +- (id)copyViolation { + id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} +} +@end + diff --git a/clang/test/Analysis/retain-release-path-notes.m b/clang/test/Analysis/retain-release-path-notes.m new file mode 100644 index 0000000..c3f5fcd --- /dev/null +++ b/clang/test/Analysis/retain-release-path-notes.m @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s + +// This actually still works after the pseudo-object refactor, it just +// uses messages that say 'method' instead of 'property'. Ted wanted +// this xfailed and filed as a bug. rdar://problem/10402993 + +/*** +This file is for testing the path-sensitive notes for retain/release errors. +Its goal is to have simple branch coverage of any path-based diagnostics, +not to actually check all possible retain/release errors. + +This file includes notes that only appear in a ref-counted analysis. +GC-specific notes should go in retain-release-path-notes-gc.m. +***/ + +@interface NSObject ++ (id)alloc; +- (id)init; +- (void)dealloc; + +- (Class)class; + +- (id)retain; +- (void)release; +- (void)autorelease; +@end + +@interface Foo : NSObject +- (id)methodWithValue; +@property(retain) id propertyValue; +@end + +typedef struct CFType *CFTypeRef; +CFTypeRef CFRetain(CFTypeRef); +void CFRelease(CFTypeRef); + +id NSMakeCollectable(CFTypeRef); +CFTypeRef CFMakeCollectable(CFTypeRef); + +CFTypeRef CFCreateSomething(); +CFTypeRef CFGetSomething(); + + +void creationViaAlloc () { + id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void creationViaCFCreate () { + CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void acquisitionViaMethod (Foo *foo) { + id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}} + [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} + [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}} + [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void acquisitionViaProperty (Foo *foo) { + id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}} + [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void acquisitionViaCFFunction () { + CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} + CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +void explicitDealloc () { + id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}} + [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} +} + +void implicitDealloc () { + id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + [object release]; // expected-note{{Object released}} + [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} +} + +void overAutorelease () { + id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + [object autorelease]; // expected-note{{Object sent -autorelease message}} + [object autorelease]; // expected-note{{Object sent -autorelease message}} + return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}} +} + +void autoreleaseUnowned (Foo *foo) { + id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} + [object autorelease]; // expected-note{{Object sent -autorelease message}} + return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}} +} + +void makeCollectableIgnored () { + CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}} + NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}} + return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} +} + +CFTypeRef CFCopyRuleViolation () { + CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} + return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} +} + +CFTypeRef CFGetRuleViolation () { + CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}} +} + +@implementation Foo (FundamentalMemoryManagementRules) +- (id)copyViolation { + id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} + return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} +} + +- (id)getViolation { + id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} + return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}} +} + +- (id)copyAutorelease { + id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + [result autorelease]; // expected-note{{Object sent -autorelease message}} + return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} +} +@end diff --git a/clang/test/Analysis/retain-release-region-store.m b/clang/test/Analysis/retain-release-region-store.m new file mode 100644 index 0000000..9173813 --- /dev/null +++ b/clang/test/Analysis/retain-release-region-store.m @@ -0,0 +1,257 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-max-loop 6 -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 <NSObject> {} +- (id)init; ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +typedef float CGFloat; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (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 = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&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 NSNumber : NSObject +- (id)initWithInt:(int)value; +@end +typedef unsigned long NSUInteger; +@interface NSArray : NSObject +-(id) initWithObjects:(const id *)objects count:(NSUInteger) cnt; +@end + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +// Test to see if we *issue* an error when we store the pointer +// to a struct. This differs from basic store. + +CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); + +struct foo { + NSDate* f; +}; + +// FIXME: We should be warning about a use-after-free here, but we +// temporarily "escape" retain counted objects stored to structs very eagerly +// until we can properly tell whether they have escaped via a return value +// or not. +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]; + // FIXME: the following line should warn. + t = CFDateGetAbsoluteTime(date); // no-warning + 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 + +//===------------------------------------------------------------------------------------------===// +// <rdar://problem/7257223> (also <rdar://problem/7283470>) - False positive due to not invalidating +// the reference count of a tracked region that was itself invalidated. +//===------------------------------------------------------------------------------------------===// + +typedef struct __rdar_7257223 { CFDateRef x; } RDar7257223; +void rdar_7257223_aux(RDar7257223 *p); + +CFDateRef rdar7257223_Create(void) { + RDar7257223 s; + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + s.x = CFDateCreate(0, t); // no-warning + rdar_7257223_aux(&s); + return s.x; +} + +CFDateRef rdar7257223_Create_2(void) { + RDar7257223 s; + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + s.x = CFDateCreate(0, t); // no-warning + return s.x; +} + +void rdar7283470(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; +} + +void rdar7283470_positive(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:2], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:3], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:4], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:5] // expected-warning{{leak}} + }; +} + +void rdar7283470_2(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + NSArray *s_numbers =[[NSArray alloc] initWithObjects:&numbers[0] count:sizeof(numbers) / sizeof(numbers[0])]; + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; + + [s_numbers release]; +} + +void rdar7283470_2_positive(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + NSArray *s_numbers =[[NSArray alloc] initWithObjects: &numbers[0] count:sizeof(numbers) / sizeof(numbers[0])]; // expected-warning{{leak}} + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; +} + +void pr6699(int x) { + CFDateRef values[2]; + values[0] = values[1] = 0; + + if (x) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + values[1] = CFDateCreate(0, t); + } + + if (values[1]) { + // A bug in RegionStore::RemoveDeadBindings caused 'values[1]' to get prematurely + // pruned from the store. + CFRelease(values[1]); // no-warning + } +} + +// <rdar://problem/8261992> Idempotent operation checker false positive with ObjC ivars +@interface R8261992 : NSObject { + @package int myIvar; +} +@end + +static void R8261992_ChangeMyIvar(R8261992 *tc) { + tc->myIvar = 5; +} + +void R8261992_test(R8261992 *tc) { + int temp = tc->myIvar; + // The ivar binding for tc->myIvar gets invalidated. + R8261992_ChangeMyIvar(tc); + tc->myIvar = temp; // no-warning + tc = [[R8261992 alloc] init]; + temp = tc->myIvar; // no-warning + // The ivar binding for tc->myIvar gets invalidated. + R8261992_ChangeMyIvar(tc); + tc->myIvar = temp; + [tc release]; // no-warning + // did we analyze this? + int *p = 0x0; + *p = 0xDEADBEEF; // expected-warning{{null}} +} + diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m new file mode 100644 index 0000000..06c510e --- /dev/null +++ b/clang/test/Analysis/retain-release.m @@ -0,0 +1,1741 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -Wno-objc-root-class %s + +#if __has_feature(attribute_ns_returns_retained) +#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) +#endif +#if __has_feature(attribute_cf_returns_retained) +#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +#endif +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#endif +#if __has_feature(attribute_cf_returns_not_retained) +#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) +#endif +#if __has_feature(attribute_ns_consumes_self) +#define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) +#endif +#if __has_feature(attribute_ns_consumed) +#define NS_CONSUMED __attribute__((ns_consumed)) +#endif +#if __has_feature(attribute_cf_consumed) +#define CF_CONSUMED __attribute__((cf_consumed)) +#endif + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +// +// #include <Cocoa/Cocoa.h> +// #include <CoreFoundation/CoreFoundation.h> +// #include <DiskArbitration/DiskArbitration.h> +// #include <QuartzCore/QuartzCore.h> +// #include <Quartz/Quartz.h> +// #include <IOKit/IOKitLib.h> +// +// It includes the basic definitions for the test cases below. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long uintptr_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned int UInt32; +typedef signed long CFIndex; +typedef CFIndex CFByteOrder; +typedef struct { + CFIndex location; + CFIndex length; +} CFRange; +static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) { + CFRange range; + range.location = loc; + range.length = len; + return range; +} +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 struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +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 int kern_return_t; +typedef kern_return_t mach_error_t; +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 const struct __CFAttributedString *CFAttributedStringRef; +typedef struct __CFAttributedString *CFMutableAttributedStringRef; +extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ; +extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ; +extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (oneway void)release; +- (id)autorelease; +- (NSString *)description; +- (id)init; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end +@class NSString, NSDictionary; +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (NSUInteger)count; +- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt; ++ (id)arrayWithObject:(id)anObject; ++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; ++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithArray:(NSArray *)array; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; +- (NSString *)stringByAppendingString:(NSString *)aString; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @class NSString, NSURL, NSError; +@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary; +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (NSUInteger)count; ++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; +@end +@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; +- (void)setObject:(id)anObject forKey:(id)aKey; +@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems; +@end typedef double CGFloat; +struct CGSize { +}; +typedef struct CGSize CGSize; +struct CGRect { +}; +typedef struct CGRect CGRect; +typedef mach_port_t io_object_t; +typedef char io_name_t[128]; +typedef io_object_t io_iterator_t; +typedef io_object_t io_service_t; +typedef struct IONotificationPort * IONotificationPortRef; +typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); +io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); +kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); +kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); +kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); +CFMutableDictionaryRef IOServiceMatching( const char * name ); +CFMutableDictionaryRef IOServiceNameMatching( const char * name ); +CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); +CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); +CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ); +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 NSTask : NSObject - (id)init; +@end typedef struct CGColorSpace *CGColorSpaceRef; +typedef struct CGImage *CGImageRef; +typedef struct CGLayer *CGLayerRef; +@interface NSResponder : NSObject <NSCoding> { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end @protocol NSValidatedUserInterfaceItem - (SEL)action; +@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem; +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +@interface NSApplication : NSResponder <NSUserInterfaceValidations> { +} +@end enum { +NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 }; +typedef NSUInteger NSApplicationTerminateReply; +@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView; +@interface NSCell : NSObject <NSCopying, NSCoding> { +} +@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError; +typedef struct { +} +CVTimeStamp; +@interface CIImage : NSObject <NSCoding, NSCopying> { +} +typedef int CIFormat; +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&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; +- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d; +@end extern NSString* const QCRendererEventKey; +@protocol QCCompositionRenderer - (NSDictionary*) attributes; +@end @interface QCRenderer : NSObject <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end extern NSString* const QCViewDidStartRenderingNotification; +@interface QCView : NSView <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end enum { +ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, }; +@class ICDevice; +@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device; +@end extern NSString *const ICScannerStatusWarmingUp; +@class ICScannerDevice; +@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner; +@end + +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +typedef unsigned long CFTypeID; +struct CGPoint { + CGFloat x; + CGFloat y; +}; +typedef struct CGPoint CGPoint; +typedef struct CGGradient *CGGradientRef; +typedef uint32_t CGGradientDrawingOptions; +extern CFTypeID CGGradientGetTypeID(void); +extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef + space, const CGFloat components[], const CGFloat locations[], size_t count); +extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space, + CFArrayRef colors, const CGFloat locations[]); +extern CGGradientRef CGGradientRetain(CGGradientRef gradient); +extern void CGGradientRelease(CGGradientRef gradient); +typedef struct CGContext *CGContextRef; +extern void CGContextDrawLinearGradient(CGContextRef context, + CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, + CGGradientDrawingOptions options); +extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); + +@interface NSMutableArray : NSObject +- (void)addObject:(id)object; ++ (id)array; +@end + + +//===----------------------------------------------------------------------===// +// 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()); // expected-warning {{leak}} + 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; +} + +__attribute__((cf_returns_retained)) CFDateRef f9() { + CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // no-warning + 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 + while (1) {} +} + + +// 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 when we pass NULL to CFRetain/CFRelease. +void f16(int x, CFTypeRef p) { + if (p) + return; + + if (x) { + CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}} + } + else { + CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}} + } +} + +// Test that an object is non-null after being CFRetained/CFReleased. +void f17(int x, CFTypeRef p) { + if (x) { + CFRelease(p); + if (!p) + CFRelease(0); // no-warning + } + else { + CFRetain(p); + if (!p) + CFRetain(0); // 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 a +0 retain count returned to caller where a +1 (owning) retain count is expected}} +} +@end + +// <rdar://problem/6659160> +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 <rdar://problem/6704930>. 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]; + } +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6833332> +// One build of the analyzer accidentally stopped tracking the allocated +// object after the 'retain'. +//===----------------------------------------------------------------------===// + +@interface rdar_6833332 : NSObject <NSApplicationDelegate> { + 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]; +} + +- (void)radar10102244 { + NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}} + if (window) + NSLog(@"%@", window); +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/6257780> 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 that is not owned at this point by the caller}} + [pool drain]; + return 0; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/10640253> Analyzer is confused about NSAutoreleasePool -allocWithZone:. +//===----------------------------------------------------------------------===// + +void rdar_10640253_autorelease_allocWithZone() { + NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:(NSZone*)0] init]; + (void) pool; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6866843> 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]; +} + + +//===----------------------------------------------------------------------===// +// <rdar://problem/6877235> 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 + +//===----------------------------------------------------------------------===// +//<rdar://problem/6320065> 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 a +0 retain count 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; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7129086> -awakeAfterUsingCoder: returns an owned object +// and claims the receiver +//===----------------------------------------------------------------------===// + +@interface RDar7129086 : NSObject {} @end +@implementation RDar7129086 +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder { + [self release]; // no-warning + return [NSString alloc]; // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a +// retained object +//===----------------------------------------------------------------------===// + +@interface RDar6859457 : NSObject {} +- (NSString*) NoCopyString; +- (NSString*) noCopyString; +@end + +@implementation RDar6859457 +- (NSString*) NoCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}} +- (NSString*) noCopyString { return [[NSString alloc] init]; } // expected-warning{{leak}} +@end + +void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) { + [x NoCopyString]; // no-warning + [x noCopyString]; // no-warning + [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 + +//===----------------------------------------------------------------------===// +// <rdar://problem/6893565> 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 + +//===----------------------------------------------------------------------===// +// <rdar://problem/6902710> 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}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6945561> -[CIContext createCGLayerWithSize:info:] +// misinterpreted by clang scan-build +//===----------------------------------------------------------------------===// + +void rdar6945561(CIContext *context, CGSize size, CFDictionaryRef d) { + [context createCGLayerWithSize:size info:d]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/6961230> add knowledge of IOKit functions to retain/release +// checker +//===----------------------------------------------------------------------===// + +void IOBSDNameMatching_wrapper(mach_port_t masterPort, uint32_t options, const char * bsdName) { + IOBSDNameMatching(masterPort, options, bsdName); // expected-warning{{leak}} +} + +void IOServiceMatching_wrapper(const char * name) { + IOServiceMatching(name); // expected-warning{{leak}} +} + +void IOServiceNameMatching_wrapper(const char * name) { + IOServiceNameMatching(name); // expected-warning{{leak}} +} + +CF_RETURNS_RETAINED CFDictionaryRef CreateDict(); + +void IOServiceAddNotification_wrapper(mach_port_t masterPort, const io_name_t notificationType, + mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) { + + CFDictionaryRef matching = CreateDict(); + CFRelease(matching); + IOServiceAddNotification(masterPort, notificationType, matching, // expected-warning{{used after it is released}} expected-warning{{deprecated}} + wakePort, reference, notification); +} + +void IORegistryEntryIDMatching_wrapper(uint64_t entryID ) { + IORegistryEntryIDMatching(entryID); // expected-warning{{leak}} +} + +void IOOpenFirmwarePathMatching_wrapper(mach_port_t masterPort, uint32_t options, + const char * path) { + IOOpenFirmwarePathMatching(masterPort, options, path); // expected-warning{{leak}} +} + +void IOServiceGetMatchingService_wrapper(mach_port_t masterPort) { + CFDictionaryRef matching = CreateDict(); + IOServiceGetMatchingService(masterPort, matching); + CFRelease(matching); // expected-warning{{used after it is released}} +} + +void IOServiceGetMatchingServices_wrapper(mach_port_t masterPort, io_iterator_t *existing) { + CFDictionaryRef matching = CreateDict(); + IOServiceGetMatchingServices(masterPort, matching, existing); + CFRelease(matching); // expected-warning{{used after it is released}} +} + +void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort, const io_name_t notificationType, + IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification) { + + CFDictionaryRef matching = CreateDict(); + IOServiceAddMatchingNotification(notifyPort, notificationType, matching, callback, refCon, notification); + CFRelease(matching); // expected-warning{{used after it is released}} +} + +//===----------------------------------------------------------------------===// +// Test of handling objects whose references "escape" to containers. +//===----------------------------------------------------------------------===// + +void CFDictionaryAddValue(CFMutableDictionaryRef, void *, void *); + +// <rdar://problem/6539791> +void rdar_6539791(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, (void*)value); // no-warning + CFRelease(value); + CFDictionaryAddValue(y, val_key, (void*)value); // no-warning + } +} + +// <rdar://problem/6560661> +// Same issue, except with "AppendValue" functions. +void rdar_6560661(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 +} + +// <rdar://problem/7152619> +// Same issue, excwept with "CFAttributeStringSetAttribute". +void rdar_7152619(CFStringRef str) { + CFAttributedStringRef string = CFAttributedStringCreate(kCFAllocatorDefault, str, 0); + CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 100, string); + CFRelease(string); + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} + CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 1), str, number); + [number release]; + [number retain]; + CFRelease(attrString); +} + +//===----------------------------------------------------------------------===// +// Test of handling CGGradientXXX functions. +//===----------------------------------------------------------------------===// + +void rdar_7184450(CGContextRef myContext, CGFloat x, CGPoint myStartPoint, + CGPoint myEndPoint) { + size_t num_locations = 6; + CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 }; + CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0, + x, // Start color + 207.0/255.0, 39.0/255.0, 39.0/255.0, x, + 147.0/255.0, 21.0/255.0, 22.0/255.0, x, + 175.0/255.0, 175.0/255.0, 175.0/255.0, x, + 255.0/255.0,255.0/255.0, 255.0/255.0, x, + 255.0/255.0,255.0/255.0, 255.0/255.0, x + }; // End color + + CGGradientRef myGradient = + CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), // expected-warning{{leak}} + components, locations, num_locations); + + CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint, + 0); + CGGradientRelease(myGradient); +} + +void rdar_7184450_pos(CGContextRef myContext, CGFloat x, CGPoint myStartPoint, + CGPoint myEndPoint) { + size_t num_locations = 6; + CGFloat locations[6] = { 0.0, 0.265, 0.28, 0.31, 0.36, 1.0 }; + CGFloat components[28] = { 239.0/256.0, 167.0/256.0, 170.0/256.0, + x, // Start color + 207.0/255.0, 39.0/255.0, 39.0/255.0, x, + 147.0/255.0, 21.0/255.0, 22.0/255.0, x, + 175.0/255.0, 175.0/255.0, 175.0/255.0, x, + 255.0/255.0,255.0/255.0, 255.0/255.0, x, + 255.0/255.0,255.0/255.0, 255.0/255.0, x + }; // End color + + CGGradientRef myGradient = + CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), components, locations, num_locations); // expected-warning 2 {{leak}} + + CGContextDrawLinearGradient(myContext, myGradient, myStartPoint, myEndPoint, + 0); +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7299394> clang false positive: retained instance passed to +// thread in pthread_create marked as leak +// +// Until we have full IPA, the analyzer should stop tracking the reference +// count of objects passed to pthread_create. +// +//===----------------------------------------------------------------------===// + +struct _opaque_pthread_t {}; +struct _opaque_pthread_attr_t {}; +typedef struct _opaque_pthread_t *__darwin_pthread_t; +typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t; +typedef __darwin_pthread_t pthread_t; +typedef __darwin_pthread_attr_t pthread_attr_t; + +int pthread_create(pthread_t *, const pthread_attr_t *, + void *(*)(void *), void *); + +void *rdar_7299394_start_routine(void *p) { + [((id) p) release]; + return 0; +} +void rdar_7299394(pthread_attr_t *attr, pthread_t *thread, void *args) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + pthread_create(thread, attr, rdar_7299394_start_routine, number); +} +void rdar_7299394_positive(pthread_attr_t *attr, pthread_t *thread) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7283567> False leak associated with call to +// CVPixelBufferCreateWithBytes () +// +// According to the Core Video Reference (ADC), CVPixelBufferCreateWithBytes and +// CVPixelBufferCreateWithPlanarBytes can release (via a callback) the +// pixel buffer object. These test cases show how the analyzer stops tracking +// the reference count for the objects passed for this argument. This +// could be made smarter. +//===----------------------------------------------------------------------===// + +typedef int int32_t; +typedef UInt32 FourCharCode; +typedef FourCharCode OSType; +typedef uint64_t CVOptionFlags; +typedef int32_t CVReturn; +typedef struct __CVBuffer *CVBufferRef; +typedef CVBufferRef CVImageBufferRef; +typedef CVImageBufferRef CVPixelBufferRef; +typedef void (*CVPixelBufferReleaseBytesCallback)( void *releaseRefCon, const void *baseAddress ); + +extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator, + size_t width, + size_t height, + OSType pixelFormatType, + void *baseAddress, + size_t bytesPerRow, + CVPixelBufferReleaseBytesCallback releaseCallback, + void *releaseRefCon, + CFDictionaryRef pixelBufferAttributes, + CVPixelBufferRef *pixelBufferOut) ; + +typedef void (*CVPixelBufferReleasePlanarBytesCallback)( void *releaseRefCon, const void *dataPtr, size_t dataSize, size_t numberOfPlanes, const void *planeAddresses[] ); + +extern CVReturn CVPixelBufferCreateWithPlanarBytes(CFAllocatorRef allocator, + size_t width, + size_t height, + OSType pixelFormatType, + void *dataPtr, + size_t dataSize, + size_t numberOfPlanes, + void *planeBaseAddress[], + size_t planeWidth[], + size_t planeHeight[], + size_t planeBytesPerRow[], + CVPixelBufferReleasePlanarBytesCallback releaseCallback, + void *releaseRefCon, + CFDictionaryRef pixelBufferAttributes, + CVPixelBufferRef *pixelBufferOut) ; + +extern CVReturn CVPixelBufferCreateWithBytes(CFAllocatorRef allocator, + size_t width, + size_t height, + OSType pixelFormatType, + void *baseAddress, + size_t bytesPerRow, + CVPixelBufferReleaseBytesCallback releaseCallback, + void *releaseRefCon, + CFDictionaryRef pixelBufferAttributes, + CVPixelBufferRef *pixelBufferOut) ; + +CVReturn rdar_7283567(CFAllocatorRef allocator, size_t width, size_t height, + OSType pixelFormatType, void *baseAddress, + size_t bytesPerRow, + CVPixelBufferReleaseBytesCallback releaseCallback, + CFDictionaryRef pixelBufferAttributes, + CVPixelBufferRef *pixelBufferOut) { + + // For the allocated object, it doesn't really matter what type it is + // for the purpose of this test. All we want to show is that + // this is freed later by the callback. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + + return CVPixelBufferCreateWithBytes(allocator, width, height, pixelFormatType, + baseAddress, bytesPerRow, releaseCallback, + number, // potentially released by callback + pixelBufferAttributes, pixelBufferOut) ; +} + +CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height, + OSType pixelFormatType, void *dataPtr, size_t dataSize, + size_t numberOfPlanes, void *planeBaseAddress[], + size_t planeWidth[], size_t planeHeight[], size_t planeBytesPerRow[], + CVPixelBufferReleasePlanarBytesCallback releaseCallback, + CFDictionaryRef pixelBufferAttributes, + CVPixelBufferRef *pixelBufferOut) { + + // For the allocated object, it doesn't really matter what type it is + // for the purpose of this test. All we want to show is that + // this is freed later by the callback. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + + return CVPixelBufferCreateWithPlanarBytes(allocator, + width, height, pixelFormatType, dataPtr, dataSize, + numberOfPlanes, planeBaseAddress, planeWidth, + planeHeight, planeBytesPerRow, releaseCallback, + number, // potentially released by callback + pixelBufferAttributes, pixelBufferOut) ; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7358899> False leak associated with +// CGBitmapContextCreateWithData +//===----------------------------------------------------------------------===// +typedef uint32_t CGBitmapInfo; +typedef void (*CGBitmapContextReleaseDataCallback)(void *releaseInfo, void *data); + +CGContextRef CGBitmapContextCreateWithData(void *data, + size_t width, size_t height, size_t bitsPerComponent, + size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo, + CGBitmapContextReleaseDataCallback releaseCallback, void *releaseInfo); + +void rdar_7358899(void *data, + size_t width, size_t height, size_t bitsPerComponent, + size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo, + CGBitmapContextReleaseDataCallback releaseCallback) { + + // For the allocated object, it doesn't really matter what type it is + // for the purpose of this test. All we want to show is that + // this is freed later by the callback. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + + CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, // expected-warning{{leak}} + bytesPerRow, space, bitmapInfo, releaseCallback, number); +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7265711> allow 'new', 'copy', 'alloc', 'init' prefix to +// start before '_' when determining Cocoa fundamental rule +// +// Previously the retain/release checker just skipped prefixes before the +// first '_' entirely. Now the checker honors the prefix if it results in a +// recognizable naming convention (e.g., 'new', 'init'). +//===----------------------------------------------------------------------===// + +@interface RDar7265711 {} +- (id) new_stuff; +@end + +void rdar7265711_a(RDar7265711 *x) { + id y = [x new_stuff]; // expected-warning{{leak}} +} + +void rdar7265711_b(RDar7265711 *x) { + id y = [x new_stuff]; // no-warning + [y release]; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7306898> clang thinks [NSCursor dragCopyCursor] returns a +// retained reference +//===----------------------------------------------------------------------===// + +@interface NSCursor : NSObject ++ (NSCursor *)dragCopyCursor; +@end + +void rdar7306898(void) { + // 'dragCopyCursor' does not follow Cocoa's fundamental rule. It is a noun, not an sentence + // implying a 'copy' of something. + NSCursor *c = [NSCursor dragCopyCursor]; // no-warning + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7252064> sending 'release', 'retain', etc. to a Class +// directly is not likely what the user intended +//===----------------------------------------------------------------------===// + +@interface RDar7252064 : NSObject @end +void rdar7252064(void) { + [RDar7252064 release]; // expected-warning{{The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [RDar7252064 retain]; // expected-warning{{The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [RDar7252064 autorelease]; // expected-warning{{The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [NSAutoreleasePool drain]; // expected-warning{{method '+drain' not found}} expected-warning{{The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly}} +} + +//===----------------------------------------------------------------------===// +// Tests of ownership attributes. +//===----------------------------------------------------------------------===// + +typedef NSString* MyStringTy; + +@protocol FooP; + +@interface TestOwnershipAttr : NSObject +- (NSString*) returnsAnOwnedString NS_RETURNS_RETAINED; // no-warning +- (NSString*) returnsAnOwnedCFString CF_RETURNS_RETAINED; // no-warning +- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning +- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning +- (NSString*) newStringNoAttr; +- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} +- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED; ++ (void) consume:(id) NS_CONSUMED x; ++ (void) consume2:(id) CF_CONSUMED x; +@end + +static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} + +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}} +} + +void test_attr1c(TestOwnershipAttr *X) { + NSString *str = [X newString]; // no-warning + NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}} +} + +void testattr2_a() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // expected-warning{{leak}} +} + +void testattr2_b() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // expected-warning{{leak}} +} + +void testattr2_c() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // no-warning + [x release]; +} + +void testattr3() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning + [TestOwnershipAttr consume:x]; + TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning + [TestOwnershipAttr consume2:y]; +} + +void consume_ns(id NS_CONSUMED x); +void consume_cf(id CF_CONSUMED x); + +void testattr4() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning + consume_ns(x); + TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning + consume_cf(y); +} + + +@interface MyClassTestCFAttr : NSObject {} +- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED; +- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED; +- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED; +- (CFDateRef) newCFRetainedAsCFNoAttr; +- (NSDate*) alsoReturnsRetained; +- (CFDateRef) alsoReturnsRetainedAsCF; +- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED; +@end + +CF_RETURNS_RETAINED +CFDateRef returnsRetainedCFDate() { + return CFDateCreate(0, CFAbsoluteTimeGetCurrent()); +} + +@implementation MyClassTestCFAttr +- (NSDate*) returnsCFRetained { + return (NSDate*) returnsRetainedCFDate(); // No leak. +} + +- (CFDateRef) returnsCFRetainedAsCF { + return returnsRetainedCFDate(); // No leak. +} + +- (CFDateRef) newCFRetainedAsCF { + return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; +} + +- (CFDateRef) newCFRetainedAsCFNoAttr { + return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} +} + +- (NSDate*) alsoReturnsRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} + +- (CFDateRef) alsoReturnsRetainedAsCF { + return returnsRetainedCFDate(); // expected-warning{{leak}} +} + + +- (NSDate*) returnsNSRetained { + return (NSDate*) returnsRetainedCFDate(); // no-warning +} +@end + +//===----------------------------------------------------------------------===// +// Test that leaks post-dominated by "panic" functions are not reported. +// +// <rdar://problem/5905851> do not report a leak when post-dominated by a call +// to a noreturn or panic function +//===----------------------------------------------------------------------===// + +void panic() __attribute__((noreturn)); +void panic_not_in_hardcoded_list() __attribute__((noreturn)); + +void test_panic_negative() { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}} +} + +void test_panic_positive() { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning + panic(); +} + +void test_panic_neg_2(int x) { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}} + if (x) + panic(); +} + +void test_panic_pos_2(int x) { + signed z = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning + if (x) + panic(); + if (!x) { + // This showed up in <rdar://problem/7796563>, where we silently missed checking + // the function type for noreturn. "panic()" is a hard-coded known panic function + // that isn't always noreturn. + panic_not_in_hardcoded_list(); + } +} + +//===----------------------------------------------------------------------===// +// Test uses of blocks (closures) +//===----------------------------------------------------------------------===// + +void test_blocks_1_pos(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} + ^{}(); +} + +void test_blocks_1_indirect_release(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^{ [number release]; }(); +} + +void test_blocks_1_indirect_retain(void) { + // Eventually this should be reported as a leak. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^{ [number retain]; }(); +} + +void test_blocks_1_indirect_release_via_call(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^(NSObject *o){ [o release]; }(number); +} + +void test_blocks_1_indirect_retain_via_call(void) { + // Eventually this should be reported as a leak. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^(NSObject *o){ [o retain]; }(number); +} + +//===--------------------------------------------------------------------===// +// Test sending message to super that returns an object alias. Previously +// this caused a crash in the analyzer. +//===--------------------------------------------------------------------===// + +@interface Rdar8015556 : NSObject {} @end +@implementation Rdar8015556 +- (id)retain { + return [super retain]; +} +@end + +// <rdar://problem/8272168> - Correcly handle Class<...> in Cocoa Conventions +// detector. + +@protocol Prot_R8272168 @end +Class <Prot_R8272168> GetAClassThatImplementsProt_R8272168(); +void r8272168() { + GetAClassThatImplementsProt_R8272168(); +} + +// Test case for <rdar://problem/8356342>, which in the past triggered +// a false positive. +@interface RDar8356342 +- (NSDate*) rdar8356342:(NSDate *)inValue; +@end + +@implementation RDar8356342 +- (NSDate*) rdar8356342:(NSDate*)inValue { + NSDate *outValue = inValue; + if (outValue == 0) + outValue = [[NSDate alloc] init]; // no-warning + + if (outValue != inValue) + [outValue autorelease]; + + return outValue; +} +@end + +// <rdar://problem/8724287> - This test case previously crashed because +// of a bug in BugReporter. +extern const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key); +typedef struct __CFError * CFErrorRef; +extern const CFStringRef kCFErrorUnderlyingErrorKey; +extern CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err); +static void rdar_8724287(CFErrorRef error) +{ + CFErrorRef error_to_dump; + + error_to_dump = error; + while (error_to_dump != ((void*)0)) { + CFDictionaryRef info; + + info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object}} + + if (info != ((void*)0)) { + } + + error_to_dump = (CFErrorRef) CFDictionaryGetValue(info, kCFErrorUnderlyingErrorKey); + } +} + +// <rdar://problem/9234108> - Make sure the model applies cf_consumed +// correctly in argument positions besides the first. +extern void *CFStringCreate(void); +extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value); +void rdar_9234108() { + rdar_9234108_helper(0, CFStringCreate()); +} + +// <rdar://problem/9726279> - Make sure that objc_method_family works +// to override naming conventions. +struct TwoDoubles { + double one; + double two; +}; +typedef struct TwoDoubles TwoDoubles; + +@interface NSValue (Mine) +- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles __attribute__((objc_method_family(init))); +@end + +@implementation NSValue (Mine) +- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles +{ + return [self init]; +} +@end + +void rdar9726279() { + TwoDoubles twoDoubles = { 0.0, 0.0 }; + NSValue *value = [[NSValue alloc] _prefix_initWithTwoDoubles:twoDoubles]; + [value release]; +} + +// <rdar://problem/9732321> +// Test camelcase support for CF conventions. While Core Foundation APIs +// don't use camel casing, other code is allowed to use it. +CFArrayRef camelcase_create_1() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef camelcase_createno() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}} +} + +CFArrayRef camelcase_copy() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef camelcase_copying() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}} +} + +CFArrayRef copyCamelCase() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef __copyCamelCase() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef __createCamelCase() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef camel_create() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + + +CFArrayRef camel_creat() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}} +} + +CFArrayRef camel_copy() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef camel_copyMachine() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning +} + +CFArrayRef camel_copymachine() { + return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}} +} + +// rdar://problem/8024350 +@protocol F18P +- (id) clone; +@end +@interface F18 : NSObject<F18P> @end +@interface F18(Cat) +- (id) clone NS_RETURNS_RETAINED; +@end + +@implementation F18 +- (id) clone { + return [F18 alloc]; +} +@end + +// Radar 6582778. +void rdar6582778(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + CFTypeRef vals[] = { CFDateCreate(0, t) }; // expected-warning {{leak}} +} + +CFTypeRef global; + +void rdar6582778_2(void) { + CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); + global = CFDateCreate(0, t); // no-warning +} + +// <rdar://problem/10232019> - Test that objects passed to containers +// are marked "escaped". + +void rdar10232019() { + NSMutableArray *array = [NSMutableArray array]; + + NSString *string = [[NSString alloc] initWithUTF8String:"foo"]; + [array addObject:string]; + [string release]; + + NSString *otherString = [string stringByAppendingString:@"bar"]; // no-warning + NSLog(@"%@", otherString); +} + +void rdar10232019_positive() { + NSMutableArray *array = [NSMutableArray array]; + + NSString *string = [[NSString alloc] initWithUTF8String:"foo"]; + [string release]; + + NSString *otherString = [string stringByAppendingString:@"bar"]; // expected-warning {{Reference-counted object is used after it is release}} + NSLog(@"%@", otherString); +} + +// RetainCountChecker support for XPC. +// <rdar://problem/9658496> +typedef void * xpc_object_t; +xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef cf); +void xpc_release(xpc_object_t object); + +void rdar9658496() { + CFStringRef cf; + xpc_object_t xpc; + cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning + xpc = _CFXPCCreateXPCObjectFromCFObject( cf ); + CFRelease(cf); + xpc_release(xpc); +} + +// Support annotations with method families. +@interface RDar10824732 : NSObject +- (id)initWithObj:(id CF_CONSUMED)obj; +@end + +@implementation RDar10824732 +- (id)initWithObj:(id)obj { + [obj release]; + return [super init]; +} +@end + +void rdar_10824732() { + @autoreleasepool { + NSString *obj = @"test"; + RDar10824732 *foo = [[RDar10824732 alloc] initWithObj:obj]; // no-warning + [foo release]; + } +} + +//===----------------------------------------------------------------------===// +// Test returning allocated memory in a struct. +// +// We currently don't have a general way to track pointers that "escape". +// Here we test that RetainCountChecker doesn't get excited about returning +// allocated CF objects in struct fields. +//===----------------------------------------------------------------------===// +void *malloc(size_t); +struct rdar11104566 { CFStringRef myStr; }; +struct rdar11104566 test_rdar11104566() { + CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning + struct rdar11104566 V; + V.myStr = cf; + return V; // no-warning +} + +struct rdar11104566 *test_2_rdar11104566() { + CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning + struct rdar11104566 *V = (struct rdar11104566 *) malloc(sizeof(*V)); + V->myStr = cf; + return V; // no-warning +} + +//===----------------------------------------------------------------------===// +// ObjC literals support. +//===----------------------------------------------------------------------===// + +void test_objc_arrays() { + { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY + NSObject *o = [[NSObject alloc] init]; + NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; // expected-warning {{leak}} + [o release]; + [a description]; + [o description]; + } + + { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY + NSObject *o = [[NSObject alloc] init]; + NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0]; + NSArray *a2 = [[NSArray alloc] initWithArray:a1]; // expected-warning {{leak}} + [o release]; + [a2 description]; + [o description]; + } + + { // CASE THREE -- OBJECT IN RETAINED @[] + NSObject *o = [[NSObject alloc] init]; + NSArray *a3 = [@[o] retain]; // expected-warning {{leak}} + [o release]; + [a3 description]; + [o description]; + } + + { // CASE FOUR -- OBJECT IN ARRAY CREATED BY DUPING @[] + NSObject *o = [[NSObject alloc] init]; + NSArray *a = [[NSArray alloc] initWithArray:@[o]]; // expected-warning {{leak}} + [o release]; + + [a description]; + [o description]; + } + + { // CASE FIVE -- OBJECT IN RETAINED @{} + NSValue *o = [[NSValue alloc] init]; + NSDictionary *a = [@{o : o} retain]; // expected-warning {{leak}} + [o release]; + + [a description]; + [o description]; + } +} + diff --git a/clang/test/Analysis/retain-release.mm b/clang/test/Analysis/retain-release.mm new file mode 100644 index 0000000..01727ea --- /dev/null +++ b/clang/test/Analysis/retain-release.mm @@ -0,0 +1,368 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s + +#if __has_feature(attribute_ns_returns_retained) +#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) +#endif +#if __has_feature(attribute_cf_returns_retained) +#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +#endif +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#endif +#if __has_feature(attribute_cf_returns_not_retained) +#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) +#endif +#if __has_feature(attribute_ns_consumes_self) +#define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) +#endif +#if __has_feature(attribute_ns_consumed) +#define NS_CONSUMED __attribute__((ns_consumed)) +#endif +#if __has_feature(attribute_cf_consumed) +#define CF_CONSUMED __attribute__((cf_consumed)) +#endif + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +// +// #include <Cocoa/Cocoa.h> +// #include <CoreFoundation/CoreFoundation.h> +// #include <DiskArbitration/DiskArbitration.h> +// #include <QuartzCore/QuartzCore.h> +// #include <Quartz/Quartz.h> +// #include <IOKit/IOKitLib.h> +// +// It includes the basic definitions for the test cases below. +//===----------------------------------------------------------------------===// + +typedef unsigned int __darwin_natural_t; +typedef unsigned long uintptr_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned int UInt32; +typedef signed long CFIndex; +typedef struct { + CFIndex location; + CFIndex length; +} CFRange; +static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) { + CFRange range; + range.location = loc; + range.length = len; + return range; +} +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 struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +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 int kern_return_t; +typedef kern_return_t mach_error_t; +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 const struct __CFAttributedString *CFAttributedStringRef; +typedef struct __CFAttributedString *CFMutableAttributedStringRef; +extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ; +extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ; +extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +@class NSString, Protocol; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (id)retain; +- (id)copy; +- (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 <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +- (id)init; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString, NSDictionary; +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end typedef unsigned short unichar; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @class NSString, NSURL, NSError; +@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary; +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (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; +@end typedef double CGFloat; +struct CGSize { +}; +typedef struct CGSize CGSize; +struct CGRect { +}; +typedef struct CGRect CGRect; +typedef mach_port_t io_object_t; +typedef char io_name_t[128]; +typedef io_object_t io_iterator_t; +typedef io_object_t io_service_t; +typedef struct IONotificationPort * IONotificationPortRef; +typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); +io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); +kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); +kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); +kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); +CFMutableDictionaryRef IOServiceMatching( const char * name ); +CFMutableDictionaryRef IOServiceNameMatching( const char * name ); +CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); +CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); +CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ); +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 NSTask : NSObject - (id)init; +@end typedef struct CGColorSpace *CGColorSpaceRef; +typedef struct CGImage *CGImageRef; +typedef struct CGLayer *CGLayerRef; +@interface NSResponder : NSObject <NSCoding> { +} +@end @protocol NSAnimatablePropertyContainer - (id)animator; +@end extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder <NSAnimatablePropertyContainer> { +} +@end @protocol NSValidatedUserInterfaceItem - (SEL)action; +@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem; +@end @class NSDate, NSDictionary, NSError, NSException, NSNotification; +@interface NSApplication : NSResponder <NSUserInterfaceValidations> { +} +@end enum { +NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 }; +typedef NSUInteger NSApplicationTerminateReply; +@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView; +@interface NSCell : NSObject <NSCopying, NSCoding> { +} +@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError; +typedef struct { +} +CVTimeStamp; +@interface CIImage : NSObject <NSCoding, NSCopying> { +} +typedef int CIFormat; +@end enum { +kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&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; +- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d; +@end extern NSString* const QCRendererEventKey; +@protocol QCCompositionRenderer - (NSDictionary*) attributes; +@end @interface QCRenderer : NSObject <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end extern NSString* const QCViewDidStartRenderingNotification; +@interface QCView : NSView <QCCompositionRenderer> { +} +- (id) createSnapshotImageOfType:(NSString*)type; +@end enum { +ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, }; +@class ICDevice; +@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device; +@end extern NSString *const ICScannerStatusWarmingUp; +@class ICScannerDevice; +@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner; +@end + +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +typedef unsigned long CFTypeID; +struct CGPoint { + CGFloat x; + CGFloat y; +}; +typedef struct CGPoint CGPoint; +typedef struct CGGradient *CGGradientRef; +typedef uint32_t CGGradientDrawingOptions; +extern CFTypeID CGGradientGetTypeID(void); +extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef + space, const CGFloat components[], const CGFloat locations[], size_t count); +extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space, + CFArrayRef colors, const CGFloat locations[]); +extern CGGradientRef CGGradientRetain(CGGradientRef gradient); +extern void CGGradientRelease(CGGradientRef gradient); +typedef struct CGContext *CGContextRef; +extern void CGContextDrawLinearGradient(CGContextRef context, + CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, + CGGradientDrawingOptions options); +extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); + +//===----------------------------------------------------------------------===// +// Test cases. +//===----------------------------------------------------------------------===// + +class SmartPointer { + id x; +public: + SmartPointer(id x) : x(x) {} + ~SmartPointer() { [x release]; } + + void adopt(id x); + void noAdopt(id x); +}; + +void test_positive() { + id x = [[NSObject alloc] init]; // expected-warning {{leak}} +} + +void test_smartpointer_1() { + id x = [[NSObject alloc] init]; // no-warning + SmartPointer foo(x); +} + +void test_smartpointer_2() { + id x = [[NSObject alloc] init]; // no-warning + SmartPointer foo(0); + foo.adopt(x); +} + +// FIXME: Eventually we want annotations to say whether or not +// a C++ method claims ownership of an Objective-C object. +void test_smartpointer_3() { + id x = [[NSObject alloc] init]; // no-warning + SmartPointer foo(0); + foo.noAdopt(x); +} + +void test_smartpointer_4() { + id x = [[NSObject alloc] init]; // no-warning + SmartPointer *foo = new SmartPointer(x); + delete foo; +} + +extern CFStringRef ElectronMicroscopyEngage(void); +void test_microscopy() { + NSString *token = (NSString*) ElectronMicroscopyEngage(); + [token release]; // expected-warning {{object that is not owned}} +} + +extern CFStringRef Scopy(void); +void test_Scopy() { + NSString *token = (NSString*) Scopy(); + [token release]; // expected-warning {{object that is not owned}} +} + +//===----------------------------------------------------------------------===// +// Test handling of template functions used to do magic with +// tracked retained pointers. +//===----------------------------------------------------------------------===// + +template <typename T, typename U> T static_objc_cast(U* value) +{ + // ...debugging code omitted... + return static_cast<T>(value); +} + +int rdar10553686(void) +{ + NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]); + [bar release]; + return 0; +} +int rdar10553686_positive(void) +{ + NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]); + [bar release]; + [bar retain]; // expected-warning {{used after it is released}} + return 0; +} + +@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration> +@end +extern void *NSMapGet(NSMapTable *table, const void *key); +extern void NSMapInsert(NSMapTable *table, const void *key, const void *value); +extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value); +char *strdup(const char *s); + +NSString * radar11152419(NSString *string1, NSString *key1, NSMapTable *map) { + NSString *string = ( NSString *)NSMapGet(map, key1); + if (!string) { + string = [string1 copy]; + NSString *key = [key1 copy]; + NSMapInsert(map, (void*) key, (void*)string); // no warning + NSMapInsertKnownAbsent(map, (void*)key, (void*)string); // no warning + } + return string; +} + diff --git a/clang/test/Analysis/security-syntax-checks-no-emit.c b/clang/test/Analysis/security-syntax-checks-no-emit.c new file mode 100644 index 0000000..c2869ca --- /dev/null +++ b/clang/test/Analysis/security-syntax-checks-no-emit.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify + +// This file complements 'security-syntax-checks.m', but tests that we omit +// specific checks on platforms where they don't make sense. + +// Omit the 'rand' check since 'arc4random' is not available on Linux. +int rand(void); +double drand48(void); +double erand48(unsigned short[3]); +long jrand48(unsigned short[3]); +void lcong48(unsigned short[7]); +long lrand48(void); +long mrand48(void); +long nrand48(unsigned short[3]); +long random(void); +int rand_r(unsigned *); + +void test_rand() +{ + unsigned short a[7]; + unsigned b; + + rand(); // no-warning + drand48(); // no-warning + erand48(a); // no-warning + jrand48(a); // no-warning + lcong48(a); // no-warning + lrand48(); // no-warning + mrand48(); // no-warning + nrand48(a); // no-warning + rand_r(&b); // no-warning + random(); // no-warning +} diff --git a/clang/test/Analysis/security-syntax-checks.m b/clang/test/Analysis/security-syntax-checks.m new file mode 100644 index 0000000..f4ccefe --- /dev/null +++ b/clang/test/Analysis/security-syntax-checks.m @@ -0,0 +1,199 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify + +#ifdef USE_BUILTINS +# define BUILTIN(f) __builtin_ ## f +#else /* USE_BUILTINS */ +# define BUILTIN(f) f +#endif /* USE_BUILTINS */ + +typedef typeof(sizeof(int)) size_t; + + +// <rdar://problem/6336718> rule request: floating point used as loop +// condition (FLP30-C, FLP-30-CPP) +// +// For reference: https://www.securecoding.cert.org/confluence/display/seccode/FLP30-C.+Do+not+use+floating+point+variables+as+loop+counters +// +void test_float_condition() { + for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // expected-warning{{Variable 'x' with floating point type 'float'}} + for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {} // expected-warning{{Variable 'x' with floating point type 'float'}} + for (float x = 100000001.0f; x <= 100000010.0f; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'float'}} + for (double x = 100000001.0; x <= 100000010.0; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'double'}} + for (double x = 100000001.0; ((x)) <= 100000010.0; ((x))++ ) {} // expected-warning{{Variable 'x' with floating point type 'double'}} + + for (double x = 100000001.0; 100000010.0 >= x; x = x + 1.0 ) {} // expected-warning{{Variable 'x' with floating point type 'double'}} + + int i = 0; + for (double x = 100000001.0; ((x)) <= 100000010.0; ((x))++, ++i ) {} // expected-warning{{Variable 'x' with floating point type 'double'}} + + typedef float FooType; + for (FooType x = 100000001.0f; x <= 100000010.0f; x++ ) {} // expected-warning{{Variable 'x' with floating point type 'FooType'}} +} + +// <rdar://problem/6335715> rule request: gets() buffer overflow +// Part of recommendation: 300-BSI (buildsecurityin.us-cert.gov) +char* gets(char *buf); + +void test_gets() { + char buff[1024]; + gets(buff); // expected-warning{{Call to function 'gets' is extremely insecure as it can always result in a buffer overflow}} +} + +int getpw(unsigned int uid, char *buf); + +void test_getpw() { + char buff[1024]; + getpw(2, buff); // expected-warning{{The getpw() function is dangerous as it may overflow the provided buffer. It is obsoleted by getpwuid().}} +} + +// <rdar://problem/6337132> CWE-273: Failure to Check Whether Privileges Were +// Dropped Successfully +typedef unsigned int __uint32_t; +typedef __uint32_t __darwin_uid_t; +typedef __uint32_t __darwin_gid_t; +typedef __darwin_uid_t uid_t; +typedef __darwin_gid_t gid_t; +int setuid(uid_t); +int setregid(gid_t, gid_t); +int setreuid(uid_t, uid_t); +extern void check(int); +void abort(void); + +void test_setuid() +{ + setuid(2); // expected-warning{{The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges}} + setuid(0); // expected-warning{{The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges}} + if (setuid (2) != 0) + abort(); + + // Currently the 'setuid' check is not flow-sensitive, and only looks + // at whether the function was called in a compound statement. This + // will lead to false negatives, but there should be no false positives. + int t = setuid(2); // no-warning + (void)setuid (2); // no-warning + + check(setuid (2)); // no-warning + + setreuid(2,2); // expected-warning{{The return value from the call to 'setreuid' is not checked. If an error occurs in 'setreuid', the following code may execute with unexpected privileges}} + setregid(2,2); // expected-warning{{The return value from the call to 'setregid' is not checked. If an error occurs in 'setregid', the following code may execute with unexpected privileges}} +} + +// <rdar://problem/6337100> CWE-338: Use of cryptographically weak prng +int rand(void); +double drand48(void); +double erand48(unsigned short[3]); +long jrand48(unsigned short[3]); +void lcong48(unsigned short[7]); +long lrand48(void); +long mrand48(void); +long nrand48(unsigned short[3]); +long random(void); +int rand_r(unsigned *); + +void test_rand() +{ + unsigned short a[7]; + unsigned b; + + rand(); // expected-warning{{Function 'rand' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + drand48(); // expected-warning{{Function 'drand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + erand48(a); // expected-warning{{Function 'erand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + jrand48(a); // expected-warning{{Function 'jrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + lcong48(a); // expected-warning{{Function 'lcong48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + lrand48(); // expected-warning{{Function 'lrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + mrand48(); // expected-warning{{Function 'mrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + nrand48(a); // expected-warning{{Function 'nrand48' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + rand_r(&b); // expected-warning{{Function 'rand_r' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} + random(); // expected-warning{{The 'random' function produces a sequence of values that an adversary may be able to predict. Use 'arc4random' instead}} +} + +char *mktemp(char *buf); + +void test_mktemp() { + char *x = mktemp("/tmp/zxcv"); // expected-warning{{Call to function 'mktemp' is insecure as it always creates or uses insecure temporary file}} +} + + +//===----------------------------------------------------------------------=== +// strcpy() +//===----------------------------------------------------------------------=== +#ifdef VARIANT + +#define __strcpy_chk BUILTIN(__strcpy_chk) +char *__strcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen); + +#define strcpy(a,b) __strcpy_chk(a,b,(size_t)-1) + +#else /* VARIANT */ + +#define strcpy BUILTIN(strcpy) +char *strcpy(char *restrict s1, const char *restrict s2); + +#endif /* VARIANT */ + +void test_strcpy() { + char x[4]; + char *y; + + strcpy(x, y); //expected-warning{{Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119.}} +} + +//===----------------------------------------------------------------------=== +// strcat() +//===----------------------------------------------------------------------=== +#ifdef VARIANT + +#define __strcat_chk BUILTIN(__strcat_chk) +char *__strcat_chk(char *restrict s1, const char *restrict s2, size_t destlen); + +#define strcat(a,b) __strcat_chk(a,b,(size_t)-1) + +#else /* VARIANT */ + +#define strcat BUILTIN(strcat) +char *strcat(char *restrict s1, const char *restrict s2); + +#endif /* VARIANT */ + +void test_strcat() { + char x[4]; + char *y; + + strcat(x, y); //expected-warning{{Call to function 'strcat' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcat'. CWE-119.}} +} + +//===----------------------------------------------------------------------=== +// vfork() +//===----------------------------------------------------------------------=== +typedef int __int32_t; +typedef __int32_t pid_t; +pid_t vfork(void); + +void test_vfork() { + vfork(); //expected-warning{{Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process.}} +} + +//===----------------------------------------------------------------------=== +// mkstemp() +//===----------------------------------------------------------------------=== + +char *mkdtemp(char *template); +int mkstemps(char *template, int suffixlen); +int mkstemp(char *template); +char *mktemp(char *template); + +void test_mkstemp() { + mkstemp("XX"); // expected-warning {{Call to 'mkstemp' should have at least 6 'X's in the format string to be secure (2 'X's seen)}} + mkstemp("XXXXXX"); + mkstemp("XXXXXXX"); + mkstemps("XXXXXX", 0); + mkstemps("XXXXXX", 1); // expected-warning {{5 'X's seen}} + mkstemps("XXXXXX", 2); // expected-warning {{Call to 'mkstemps' should have at least 6 'X's in the format string to be secure (4 'X's seen, 2 characters used as a suffix)}} + mkdtemp("XX"); // expected-warning {{2 'X's seen}} + mkstemp("X"); // expected-warning {{Call to 'mkstemp' should have at least 6 'X's in the format string to be secure (1 'X' seen)}} + mkdtemp("XXXXXX"); +} + diff --git a/clang/test/Analysis/self-init.m b/clang/test/Analysis/self-init.m new file mode 100644 index 0000000..d515173 --- /dev/null +++ b/clang/test/Analysis/self-init.m @@ -0,0 +1,256 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties %s -verify + +@class NSZone, NSCoder; +@protocol NSObject- (id)self; +@end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +-(id)class; +-(id)init; +-(id)release; +@end +@interface NSProxy <NSObject> {} +@end + +//#import "Foundation/NSObject.h" +typedef unsigned NSUInteger; +typedef long NSInteger; + +@interface NSInvocation : NSObject {} +- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx; +- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx; +@end + +@class NSMethodSignature, NSCoder, NSString, NSEnumerator; +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (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; + +@interface NSBundle : NSObject ++(id)loadNibNamed:(NSString*)s owner:(id)o; +@end + +void log(void *obj); +extern void *somePtr; + +@class MyObj; +extern id _commonInit(MyObj *self); + +@interface MyObj : NSObject { + id myivar; + int myint; +} +-(id)_init; +-(id)initWithSomething:(int)x; +-(void)doSomething; ++(id)commonInitMember:(id)s; +@end + +@interface MyProxyObj : NSProxy {} +-(id)init; +@end + +@implementation MyObj + +-(id)init { + do { if (!((somePtr != 0))) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:"init.m"] lineNumber:21 description:(@"Invalid parameter not satisfying: %s"), ("x != 0"), (0), (0), (0), (0)]; } } while(0); + return [self initWithSomething:0]; +} + +-(id)init2 { + self = [self initWithSomething:0]; + return self; +} + +-(id)init3 { + log([self class]); + return [self initWithSomething:0]; +} + +-(id)init4 { + self = [super init]; + if (self) { + log(&self); + } + return self; +} + +-(id)init4_w { + [super init]; + if (self) { + log(&self); + } + return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self) init...]'}} +} + +- (id)initWithSomething:(int)x { + if ((self = [super init])) + myint = x; + return self; +} + +-(id)_init { + myivar = 0; + return self; +} + +-(id)init5 { + [NSBundle loadNibNamed:@"Window" owner:self]; + return [self initWithSomething:0]; +} + +-(id)init6 { + [NSBundle loadNibNamed:@"Window" owner:myivar]; // no-warning + return [self initWithSomething:0]; +} + +-(id)init7 { + if (0 != (self = [self _init])) + myivar = 0; + return self; +} + +-(id)init8 { + if ((self = [super init])) { + log(&self); + myivar = 0; + } + return self; +} + +-(id)init9 { + [self doSomething]; + return self; // no-warning +} + +-(id)init10 { + myivar = 0; // no-warning + return self; +} + +-(id)init11 { + return self; // no-warning +} + +-(id)init12 { + [super init]; + return self; // expected-warning {{Returning 'self'}} +} + +-(id)init13 { + if (self == [super init]) { + myivar = 0; // expected-warning {{Instance variable used}} + } + return self; // expected-warning {{Returning 'self'}} +} + +-(id)init14 { + if (!(self = _commonInit(self))) + return 0; + return self; +} + +-(id)init14_w { + [super init]; + self = _commonInit(self); + return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self) init...]'}} +} + +-(id)init15 { + if (!(self = [super init])) + return 0; + return self; +} + +-(id)init16 { + somePtr = [super init]; + self = somePtr; + myivar = 0; + return self; +} + +-(id)init17 { + somePtr = [super init]; + myivar = 0; // expected-warning {{Instance variable used}} + return 0; +} + +-(id)init18 { + self = [super init]; + self = _commonInit(self); + return self; +} + ++(id)commonInitMember:(id)s { + return s; +} + +-(id)init19 { + self = [super init]; + self = [MyObj commonInitMember:self]; + return self; +} + +-(id)init19_w { + [super init]; + self = [MyObj commonInitMember:self]; + return self; // expected-warning {{Returning 'self'}} +} + +-(void)doSomething {} + +@end + +@implementation MyProxyObj + +- (id)init { return self; } + +@end + + +// Test for radar://10973514 : self should not be invalidated by a method call. +@interface Test : NSObject { + NSInvocation *invocation_; +} +@end +@implementation Test +-(id) initWithTarget:(id) rec selector:(SEL) cb { + if (self=[super init]) { + [invocation_ setArgument:&self atIndex:2]; + } + return self; +} +@end + +// Test radar:11235991 - passing self to a call to super. +@protocol MyDelegate +@end +@interface Object : NSObject +- (id) initWithObject: (id)i; +@end +@interface Derived: Object <MyDelegate> +- (id) initWithInt: (int)t; +@property (nonatomic, retain, readwrite) Object *size; +@end +@implementation Derived +- (id) initWithInt: (int)t { + if ((self = [super initWithObject:self])) { + _size = [[Object alloc] init]; + } + return self; +} +@end diff --git a/clang/test/Analysis/sizeofpointer.c b/clang/test/Analysis/sizeofpointer.c new file mode 100644 index 0000000..0c86de8 --- /dev/null +++ b/clang/test/Analysis/sizeofpointer.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.SizeofPtr -verify %s + +struct s { +}; + +int f(struct s *p) { + return sizeof(p); // expected-warning{{The code calls sizeof() on a pointer type. This can produce an unexpected result.}} +} diff --git a/clang/test/Analysis/stack-addr-ps.c b/clang/test/Analysis/stack-addr-ps.c new file mode 100644 index 0000000..a443a32 --- /dev/null +++ b/clang/test/Analysis/stack-addr-ps.c @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s + +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 to caller}} +} + +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}} +} + +int array_test(int x[2]) { + return x[0]; // no-warning +} + +struct baz { + int x; + int y[2]; +}; + +int struct_test(struct baz byVal, int flag) { + if (flag) + return byVal.x; // no-warning + else { + return byVal.y[0]; // no-warning + } +} + +typedef int (^ComparatorBlock)(int a, int b); +ComparatorBlock test_return_block(void) { + // This block is a global since it has no captures. + ComparatorBlock b = ^int(int a, int b){ return a > b; }; + return b; // no-warning +} + +ComparatorBlock test_return_block_with_capture(int x) { + // This block is stack allocated because it has captures. + ComparatorBlock b = ^int(int a, int b){ return a > b + x; }; + return b; // expected-warning{{Address of stack-allocated block}} +} + +ComparatorBlock test_return_block_neg_aux(void); +ComparatorBlock test_return_block_neg(void) { + ComparatorBlock b = test_return_block_neg_aux(); + return b; // no-warning +} + +// <rdar://problem/7523821> +int *rdar_7523821_f2() { + int a[3]; + return a; // expected-warning 2 {{ddress of stack memory associated with local variable 'a' returned}} +}; + +// Handle blocks that have no captures or are otherwise declared 'static'. +// <rdar://problem/10348049> +typedef int (^RDar10348049)(int value); +RDar10348049 test_rdar10348049(void) { + static RDar10348049 b = ^int(int x) { + return x + 2; + }; + return b; // no-warning +} + diff --git a/clang/test/Analysis/stack-addr-ps.cpp b/clang/test/Analysis/stack-addr-ps.cpp new file mode 100644 index 0000000..b09e435 --- /dev/null +++ b/clang/test/Analysis/stack-addr-ps.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s + +// FIXME: Only the stack-address checking in Sema catches this right now, and +// the stack analyzer doesn't handle the ImplicitCastExpr (lvalue). +const int& g() { + int s; + return s; // expected-warning{{Address of stack memory associated with local variable 's' returned}} expected-warning{{reference to stack memory associated with local variable 's' returned}} +} + +const int& g2() { + int s1; + int &s2 = s1; // expected-note {{binding reference variable 's2' here}} + return s2; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}} +} + +const int& g3() { + int s1; + int &s2 = s1; // expected-note {{binding reference variable 's2' here}} + int &s3 = s2; // expected-note {{binding reference variable 's3' here}} + return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}} +} + +int get_value(); + +const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}} + +const int &get_reference2() { + const int &x = get_value(); // expected-note {{binding reference variable 'x' here}} + return x; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}} +} + +const int &get_reference3() { + const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}} + const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} + return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}} +} + +int global_var; +int *f1() { + int &y = global_var; + return &y; +} + +int *f2() { + int x1; + int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} + return &x2; // expected-warning{{Address of stack memory associated with local variable 'x1' returned}} expected-warning {{address of stack memory associated with local variable 'x1' returned}} +} + +int *f3() { + int x1; + int *const &x2 = &x1; // expected-note {{binding reference variable 'x2' here}} + return x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}} expected-warning {{Address of stack memory associated with local variable 'x1' returned to caller}} +} + +const int *f4() { + const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}} + const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}} + return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning address of local temporary}} +} + +struct S { + int x; +}; + +int *mf() { + S s1; + S &s2 = s1; // expected-note {{binding reference variable 's2' here}} + int &x = s2.x; // expected-note {{binding reference variable 'x' here}} + return &x; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{address of stack memory associated with local variable 's1' returned}} +} + +void *lf() { + label: + void *const &x = &&label; // expected-note {{binding reference variable 'x' here}} + return x; // expected-warning {{returning address of label, which is local}} +} + +template <typename T> +struct TS { + int *get(); + int *m() { + int *&x = get(); + return x; + } +}; diff --git a/clang/test/Analysis/stack-block-returned.cpp b/clang/test/Analysis/stack-block-returned.cpp new file mode 100644 index 0000000..af2cec7 --- /dev/null +++ b/clang/test/Analysis/stack-block-returned.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s + +typedef void (^bptr)(void); + +bptr bf(int j) { + __block int i; + const bptr &qq = ^{ i=0; }; // expected-note {{binding reference variable 'qq' here}} + return qq; // expected-error {{returning block that lives on the local stack}} +} diff --git a/clang/test/Analysis/stackaddrleak.c b/clang/test/Analysis/stackaddrleak.c new file mode 100644 index 0000000..ada0cc1 --- /dev/null +++ b/clang/test/Analysis/stackaddrleak.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s + +char const *p; + +void f0() { + char const str[] = "This will change"; + p = str; // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}} +} + +void f1() { + char const str[] = "This will change"; + p = str; + p = 0; // no-warning +} + +void f2() { + p = (const char *) __builtin_alloca(12); // expected-warning{{Address of stack memory allocated by call to alloca() on line 17 is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}} +} + +// PR 7383 - previosly the stack address checker would crash on this example +// because it would attempt to do a direct load from 'pr7383_list'. +static int pr7383(__const char *__) +{ + return 0; +} +extern __const char *__const pr7383_list[]; + +// Test that we catch multiple returns via globals when analyzing a function. +void test_multi_return() { + static int *a, *b; + int x; + a = &x; + b = &x; // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'a' upon returning}} expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'b' upon returning}} +} diff --git a/clang/test/Analysis/stats.c b/clang/test/Analysis/stats.c new file mode 100644 index 0000000..6beadbe --- /dev/null +++ b/clang/test/Analysis/stats.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s + +void foo() { + int x; +} +// CHECK: ... Statistics Collected ... +// CHECK:100 AnalysisConsumer - The % of reachable basic blocks. +// CHECK:The # of times RemoveDeadBindings is called diff --git a/clang/test/Analysis/stream.c b/clang/test/Analysis/stream.c new file mode 100644 index 0000000..e68835e --- /dev/null +++ b/clang/test/Analysis/stream.c @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Stream -analyzer-store region -verify %s + +typedef __typeof__(sizeof(int)) size_t; +typedef struct _IO_FILE FILE; +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +extern FILE *fopen(const char *path, const char *mode); +extern FILE *tmpfile(void); +extern int fclose(FILE *fp); +extern size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +extern int fseek (FILE *__stream, long int __off, int __whence); +extern long int ftell (FILE *__stream); +extern void rewind (FILE *__stream); + +void f1(void) { + FILE *p = fopen("foo", "r"); + char buf[1024]; + fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL.}} + fclose(p); +} + +void f2(void) { + FILE *p = fopen("foo", "r"); + fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL.}} + fclose(p); +} + +void f3(void) { + FILE *p = fopen("foo", "r"); + ftell(p); // expected-warning {{Stream pointer might be NULL.}} + fclose(p); +} + +void f4(void) { + FILE *p = fopen("foo", "r"); + rewind(p); // expected-warning {{Stream pointer might be NULL.}} + fclose(p); +} + +void f5(void) { + FILE *p = fopen("foo", "r"); + if (!p) + return; + fseek(p, 1, SEEK_SET); // no-warning + fseek(p, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR.}} + fclose(p); +} + +void f6(void) { + FILE *p = fopen("foo", "r"); + fclose(p); + fclose(p); // expected-warning {{Try to close a file Descriptor already closed. Cause undefined behaviour.}} +} + +void f7(void) { + FILE *p = tmpfile(); + ftell(p); // expected-warning {{Stream pointer might be NULL.}} + fclose(p); +} + +void f8(int c) { + FILE *p = fopen("foo.c", "r"); + if(c) + return; // expected-warning {{Opened File never closed. Potential Resource leak.}} + fclose(p); +} + +FILE *f9(void) { + FILE *p = fopen("foo.c", "r"); + if (p) + return p; // no-warning + else + return 0; +} + +void pr7831(FILE *fp) { + fclose(fp); // no-warning +} + +// PR 8081 - null pointer crash when 'whence' is not an integer constant +void pr8081(FILE *stream, long offset, int whence) { + fseek(stream, offset, whence); +} + diff --git a/clang/test/Analysis/string-fail.c b/clang/test/Analysis/string-fail.c new file mode 100644 index 0000000..3bff6d4 --- /dev/null +++ b/clang/test/Analysis/string-fail.c @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s +// XFAIL: * + +// This file is for tests that may eventually go into string.c, or may be +// deleted outright. At one point these tests passed, but only because we +// weren't correctly modelling the behavior of the relevant string functions. +// The tests aren't incorrect, but require the analyzer to be smarter about +// conjured values than it currently is. + +//===----------------------------------------------------------------------=== +// Declarations +//===----------------------------------------------------------------------=== + +// Some functions are so similar to each other that they follow the same code +// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is +// defined, make sure to use the variants instead to make sure they are still +// checked by the analyzer. + +// Some functions are implemented as builtins. These should be #defined as +// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. + +// Functions that have variants and are also available as builtins should be +// declared carefully! See memcpy() for an example. + +#ifdef USE_BUILTINS +# define BUILTIN(f) __builtin_ ## f +#else /* USE_BUILTINS */ +# define BUILTIN(f) f +#endif /* USE_BUILTINS */ + +#define NULL 0 +typedef typeof(sizeof(int)) size_t; + + +//===----------------------------------------------------------------------=== +// strnlen() +//===----------------------------------------------------------------------=== + +#define strnlen BUILTIN(strnlen) +size_t strnlen(const char *s, size_t maxlen); + +void strnlen_liveness(const char *x) { + if (strnlen(x, 10) < 5) + return; + if (strnlen(x, 10) < 5) + (void)*(char*)0; // no-warning +} + +void strnlen_subregion() { + struct two_stringsn { char a[2], b[2]; }; + extern void use_two_stringsn(struct two_stringsn *); + + struct two_stringsn z; + use_two_stringsn(&z); + + size_t a = strnlen(z.a, 10); + z.b[0] = 5; + size_t b = strnlen(z.a, 10); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + use_two_stringsn(&z); + + size_t c = strnlen(z.a, 10); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +extern void use_stringn(char *); +void strnlen_argument(char *x) { + size_t a = strnlen(x, 10); + size_t b = strnlen(x, 10); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + use_stringn(x); + + size_t c = strnlen(x, 10); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +extern char global_strn[]; +void strnlen_global() { + size_t a = strnlen(global_strn, 10); + size_t b = strnlen(global_strn, 10); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + // Call a function with unknown effects, which should invalidate globals. + use_stringn(0); + + size_t c = strnlen(global_strn, 10); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_indirect(char *x) { + size_t a = strnlen(x, 10); + char *p = x; + char **p2 = &p; + size_t b = strnlen(x, 10); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + extern void use_stringn_ptr(char*const*); + use_stringn_ptr(p2); + + size_t c = strnlen(x, 10); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c new file mode 100644 index 0000000..c0814b8 --- /dev/null +++ b/clang/test/Analysis/string.c @@ -0,0 +1,1124 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=experimental.security.taint,core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s + +//===----------------------------------------------------------------------=== +// Declarations +//===----------------------------------------------------------------------=== + +// Some functions are so similar to each other that they follow the same code +// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is +// defined, make sure to use the variants instead to make sure they are still +// checked by the analyzer. + +// Some functions are implemented as builtins. These should be #defined as +// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. + +// Functions that have variants and are also available as builtins should be +// declared carefully! See memcpy() for an example. + +#ifdef USE_BUILTINS +# define BUILTIN(f) __builtin_ ## f +#else /* USE_BUILTINS */ +# define BUILTIN(f) f +#endif /* USE_BUILTINS */ + +#define NULL 0 +typedef typeof(sizeof(int)) size_t; +int scanf(const char *restrict format, ...); + +//===----------------------------------------------------------------------=== +// strlen() +//===----------------------------------------------------------------------=== + +#define strlen BUILTIN(strlen) +size_t strlen(const char *s); + +void strlen_constant0() { + if (strlen("123") != 3) + (void)*(char*)0; // no-warning +} + +void strlen_constant1() { + const char *a = "123"; + if (strlen(a) != 3) + (void)*(char*)0; // no-warning +} + +void strlen_constant2(char x) { + char a[] = "123"; + if (strlen(a) != 3) + (void)*(char*)0; // no-warning + a[0] = x; + if (strlen(a) != 3) + (void)*(char*)0; // expected-warning{{null}} +} + +size_t strlen_null() { + return strlen(0); // expected-warning{{Null pointer argument in call to string length function}} +} + +size_t strlen_fn() { + return strlen((char*)&strlen_fn); // expected-warning{{Argument to string length function is the address of the function 'strlen_fn', which is not a null-terminated string}} +} + +size_t strlen_nonloc() { +label: + return strlen((char*)&&label); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} +} + +void strlen_subregion() { + struct two_strings { char a[2], b[2]; }; + extern void use_two_strings(struct two_strings *); + + struct two_strings z; + use_two_strings(&z); + + size_t a = strlen(z.a); + z.b[0] = 5; + size_t b = strlen(z.a); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + use_two_strings(&z); + + size_t c = strlen(z.a); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +extern void use_string(char *); +void strlen_argument(char *x) { + size_t a = strlen(x); + size_t b = strlen(x); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + use_string(x); + + size_t c = strlen(x); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +extern char global_str[]; +void strlen_global() { + size_t a = strlen(global_str); + size_t b = strlen(global_str); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + // Call a function with unknown effects, which should invalidate globals. + use_string(0); + + size_t c = strlen(global_str); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void strlen_indirect(char *x) { + size_t a = strlen(x); + char *p = x; + char **p2 = &p; + size_t b = strlen(x); + if (a == 0 && b != 0) + (void)*(char*)0; // expected-warning{{never executed}} + + extern void use_string_ptr(char*const*); + use_string_ptr(p2); + + size_t c = strlen(x); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void strlen_indirect2(char *x) { + size_t a = strlen(x); + char *p = x; + char **p2 = &p; + extern void use_string_ptr2(char**); + use_string_ptr2(p2); + + size_t c = strlen(x); + if (a == 0 && c != 0) + (void)*(char*)0; // expected-warning{{null}} +} + +void strlen_liveness(const char *x) { + if (strlen(x) < 5) + return; + if (strlen(x) < 5) + (void)*(char*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// strnlen() +//===----------------------------------------------------------------------=== + +size_t strnlen(const char *s, size_t maxlen); + +void strnlen_constant0() { + if (strnlen("123", 10) != 3) + (void)*(char*)0; // expected-warning{{never executed}} +} + +void strnlen_constant1() { + const char *a = "123"; + if (strnlen(a, 10) != 3) + (void)*(char*)0; // expected-warning{{never executed}} +} + +void strnlen_constant2(char x) { + char a[] = "123"; + if (strnlen(a, 10) != 3) + (void)*(char*)0; // expected-warning{{never executed}} + a[0] = x; + if (strnlen(a, 10) != 3) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_constant4() { + if (strnlen("123456", 3) != 3) + (void)*(char*)0; // expected-warning{{never executed}} +} + +void strnlen_constant5() { + const char *a = "123456"; + if (strnlen(a, 3) != 3) + (void)*(char*)0; // expected-warning{{never executed}} +} + +void strnlen_constant6(char x) { + char a[] = "123456"; + if (strnlen(a, 3) != 3) + (void)*(char*)0; // expected-warning{{never executed}} + a[0] = x; + if (strnlen(a, 3) != 3) + (void)*(char*)0; // expected-warning{{null}} +} + +size_t strnlen_null() { + return strnlen(0, 3); // expected-warning{{Null pointer argument in call to string length function}} +} + +size_t strnlen_fn() { + return strnlen((char*)&strlen_fn, 3); // expected-warning{{Argument to string length function is the address of the function 'strlen_fn', which is not a null-terminated string}} +} + +size_t strnlen_nonloc() { +label: + return strnlen((char*)&&label, 3); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} +} + +void strnlen_zero() { + if (strnlen("abc", 0) != 0) + (void)*(char*)0; // expected-warning{{never executed}} + if (strnlen(NULL, 0) != 0) // no-warning + (void)*(char*)0; // no-warning +} + +size_t strnlen_compound_literal() { + // This used to crash because we don't model the string lengths of + // compound literals. + return strnlen((char[]) { 'a', 'b', 0 }, 1); +} + +size_t strnlen_unknown_limit(float f) { + // This used to crash because we don't model the integer values of floats. + return strnlen("abc", (int)f); +} + +void strnlen_is_not_strlen(char *x) { + if (strnlen(x, 10) != strlen(x)) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_at_limit(char *x) { + size_t len = strnlen(x, 10); + if (len > 10) + (void)*(char*)0; // expected-warning{{never executed}} + if (len == 10) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_less_than_limit(char *x) { + size_t len = strnlen(x, 10); + if (len > 10) + (void)*(char*)0; // expected-warning{{never executed}} + if (len < 10) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_at_actual(size_t limit) { + size_t len = strnlen("abc", limit); + if (len > 3) + (void)*(char*)0; // expected-warning{{never executed}} + if (len == 3) + (void)*(char*)0; // expected-warning{{null}} +} + +void strnlen_less_than_actual(size_t limit) { + size_t len = strnlen("abc", limit); + if (len > 3) + (void)*(char*)0; // expected-warning{{never executed}} + if (len < 3) + (void)*(char*)0; // expected-warning{{null}} +} + +//===----------------------------------------------------------------------=== +// strcpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __strcpy_chk BUILTIN(__strcpy_chk) +char *__strcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen); + +#define strcpy(a,b) __strcpy_chk(a,b,(size_t)-1) + +#else /* VARIANT */ + +#define strcpy BUILTIN(strcpy) +char *strcpy(char *restrict s1, const char *restrict s2); + +#endif /* VARIANT */ + + +void strcpy_null_dst(char *x) { + strcpy(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strcpy_null_src(char *x) { + strcpy(x, NULL); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strcpy_fn(char *x) { + strcpy(x, (char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}} +} + +void strcpy_fn_const(char *x) { + strcpy(x, (const char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}} +} + +void strcpy_effects(char *x, char *y) { + char a = x[0]; + + if (strcpy(x, y) != x) + (void)*(char*)0; // no-warning + + if (strlen(x) != strlen(y)) + (void)*(char*)0; // no-warning + + if (a != x[0]) + (void)*(char*)0; // expected-warning{{null}} +} + +void strcpy_overflow(char *y) { + char x[4]; + if (strlen(y) == 4) + strcpy(x, y); // expected-warning{{String copy function overflows destination buffer}} +} + +void strcpy_no_overflow(char *y) { + char x[4]; + if (strlen(y) == 3) + strcpy(x, y); // no-warning +} + +//===----------------------------------------------------------------------=== +// stpcpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __stpcpy_chk BUILTIN(__stpcpy_chk) +char *__stpcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen); + +#define stpcpy(a,b) __stpcpy_chk(a,b,(size_t)-1) + +#else /* VARIANT */ + +#define stpcpy BUILTIN(stpcpy) +char *stpcpy(char *restrict s1, const char *restrict s2); + +#endif /* VARIANT */ + + +void stpcpy_effect(char *x, char *y) { + char a = x[0]; + + if (stpcpy(x, y) != &x[strlen(y)]) + (void)*(char*)0; // no-warning + + if (strlen(x) != strlen(y)) + (void)*(char*)0; // no-warning + + if (a != x[0]) + (void)*(char*)0; // expected-warning{{null}} +} + +void stpcpy_overflow(char *y) { + char x[4]; + if (strlen(y) == 4) + stpcpy(x, y); // expected-warning{{String copy function overflows destination buffer}} +} + +void stpcpy_no_overflow(char *y) { + char x[4]; + if (strlen(y) == 3) + stpcpy(x, y); // no-warning +} + +//===----------------------------------------------------------------------=== +// strcat() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __strcat_chk BUILTIN(__strcat_chk) +char *__strcat_chk(char *restrict s1, const char *restrict s2, size_t destlen); + +#define strcat(a,b) __strcat_chk(a,b,(size_t)-1) + +#else /* VARIANT */ + +#define strcat BUILTIN(strcat) +char *strcat(char *restrict s1, const char *restrict s2); + +#endif /* VARIANT */ + + +void strcat_null_dst(char *x) { + strcat(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strcat_null_src(char *x) { + strcat(x, NULL); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strcat_fn(char *x) { + strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcat_fn', which is not a null-terminated string}} +} + +void strcat_effects(char *y) { + char x[8] = "123"; + size_t orig_len = strlen(x); + char a = x[0]; + + if (strlen(y) != 4) + return; + + if (strcat(x, y) != x) + (void)*(char*)0; // no-warning + + if ((int)strlen(x) != (orig_len + strlen(y))) + (void)*(char*)0; // no-warning +} + +void strcat_overflow_0(char *y) { + char x[4] = "12"; + if (strlen(y) == 4) + strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} +} + +void strcat_overflow_1(char *y) { + char x[4] = "12"; + if (strlen(y) == 3) + strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} +} + +void strcat_overflow_2(char *y) { + char x[4] = "12"; + if (strlen(y) == 2) + strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} +} + +void strcat_no_overflow(char *y) { + char x[5] = "12"; + if (strlen(y) == 2) + strcat(x, y); // no-warning +} + +void strcat_symbolic_dst_length(char *dst) { + strcat(dst, "1234"); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning +} + +void strcat_symbolic_src_length(char *src) { + char dst[8] = "1234"; + strcat(dst, src); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning +} + +void strcat_symbolic_dst_length_taint(char *dst) { + scanf("%s", dst); // Taint data. + strcat(dst, "1234"); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning +} + +void strcat_unknown_src_length(char *src, int offset) { + char dst[8] = "1234"; + strcat(dst, &src[offset]); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning +} + +// There is no strcat_unknown_dst_length because if we can't get a symbolic +// length for the "before" strlen, we won't be able to set one for "after". + +void strcat_too_big(char *dst, char *src) { + if (strlen(dst) != (((size_t)0) - 2)) + return; + if (strlen(src) != 2) + return; + strcat(dst, src); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}} +} + + +//===----------------------------------------------------------------------=== +// strncpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __strncpy_chk BUILTIN(__strncpy_chk) +char *__strncpy_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen); + +#define strncpy(a,b,n) __strncpy_chk(a,b,n,(size_t)-1) + +#else /* VARIANT */ + +#define strncpy BUILTIN(strncpy) +char *strncpy(char *restrict s1, const char *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void strncpy_null_dst(char *x) { + strncpy(NULL, x, 5); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strncpy_null_src(char *x) { + strncpy(x, NULL, 5); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strncpy_fn(char *x) { + strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}} +} + +void strncpy_effects(char *x, char *y) { + char a = x[0]; + + if (strncpy(x, y, 5) != x) + (void)*(char*)0; // no-warning + + if (strlen(x) != strlen(y)) + (void)*(char*)0; // expected-warning{{null}} + + if (a != x[0]) + (void)*(char*)0; // expected-warning{{null}} +} + +void strncpy_overflow(char *y) { + char x[4]; + if (strlen(y) == 4) + strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}} +} + +void strncpy_no_overflow(char *y) { + char x[4]; + if (strlen(y) == 3) + strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}} +} + +void strncpy_no_overflow2(char *y, int n) { + if (n <= 4) + return; + + char x[4]; + if (strlen(y) == 3) + strncpy(x, y, n); // expected-warning{{Size argument is greater than the length of the destination buffer}} +} + +void strncpy_truncate(char *y) { + char x[4]; + if (strlen(y) == 4) + strncpy(x, y, 3); // no-warning +} + +void strncpy_no_truncate(char *y) { + char x[4]; + if (strlen(y) == 3) + strncpy(x, y, 3); // no-warning +} + +void strncpy_exactly_matching_buffer(char *y) { + char x[4]; + strncpy(x, y, 4); // no-warning + + // strncpy does not null-terminate, so we have no idea what the strlen is + // after this. + if (strlen(x) > 4) + (void)*(int*)0; // expected-warning{{null}} +} + +void strncpy_exactly_matching_buffer2(char *y) { + if (strlen(y) >= 4) + return; + + char x[4]; + strncpy(x, y, 4); // no-warning + + // This time, we know that y fits in x anyway. + if (strlen(x) > 3) + (void)*(int*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// strncat() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __strncat_chk BUILTIN(__strncat_chk) +char *__strncat_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen); + +#define strncat(a,b,c) __strncat_chk(a,b,c, (size_t)-1) + +#else /* VARIANT */ + +#define strncat BUILTIN(strncat) +char *strncat(char *restrict s1, const char *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void strncat_null_dst(char *x) { + strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strncat_null_src(char *x) { + strncat(x, NULL, 4); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void strncat_fn(char *x) { + strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string copy function is the address of the function 'strncat_fn', which is not a null-terminated string}} +} + +void strncat_effects(char *y) { + char x[8] = "123"; + size_t orig_len = strlen(x); + char a = x[0]; + + if (strlen(y) != 4) + return; + + if (strncat(x, y, strlen(y)) != x) + (void)*(char*)0; // no-warning + + if (strlen(x) != orig_len + strlen(y)) + (void)*(char*)0; // no-warning +} + +void strncat_overflow_0(char *y) { + char x[4] = "12"; + if (strlen(y) == 4) + strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +void strncat_overflow_1(char *y) { + char x[4] = "12"; + if (strlen(y) == 3) + strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +void strncat_overflow_2(char *y) { + char x[4] = "12"; + if (strlen(y) == 2) + strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +void strncat_overflow_3(char *y) { + char x[4] = "12"; + if (strlen(y) == 4) + strncat(x, y, 2); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} +void strncat_no_overflow_1(char *y) { + char x[5] = "12"; + if (strlen(y) == 2) + strncat(x, y, strlen(y)); // no-warning +} + +void strncat_no_overflow_2(char *y) { + char x[4] = "12"; + if (strlen(y) == 4) + strncat(x, y, 1); // no-warning +} + +void strncat_symbolic_dst_length(char *dst) { + strncat(dst, "1234", 5); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning +} + +void strncat_symbolic_src_length(char *src) { + char dst[8] = "1234"; + strncat(dst, src, 3); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning + + char dst2[8] = "1234"; + strncat(dst2, src, 4); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +void strncat_unknown_src_length(char *src, int offset) { + char dst[8] = "1234"; + strncat(dst, &src[offset], 3); + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning + + char dst2[8] = "1234"; + strncat(dst2, &src[offset], 4); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +// There is no strncat_unknown_dst_length because if we can't get a symbolic +// length for the "before" strlen, we won't be able to set one for "after". + +void strncat_symbolic_limit(unsigned limit) { + char dst[6] = "1234"; + char src[] = "567"; + strncat(dst, src, limit); // no-warning + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning + if (strlen(dst) == 4) + (void)*(char*)0; // expected-warning{{null}} +} + +void strncat_unknown_limit(float limit) { + char dst[6] = "1234"; + char src[] = "567"; + strncat(dst, src, (size_t)limit); // no-warning + if (strlen(dst) < 4) + (void)*(char*)0; // no-warning + if (strlen(dst) == 4) + (void)*(char*)0; // expected-warning{{null}} +} + +void strncat_too_big(char *dst, char *src) { + if (strlen(dst) != (((size_t)0) - 2)) + return; + if (strlen(src) != 2) + return; + strncat(dst, src, 2); // expected-warning{{This expression will create a string whose length is too big to be represented as a size_t}} +} + +//===----------------------------------------------------------------------=== +// strcmp() +//===----------------------------------------------------------------------=== + +#define strcmp BUILTIN(strcmp) +int strcmp(const char * s1, const char * s2); + +void strcmp_constant0() { + if (strcmp("123", "123") != 0) + (void)*(char*)0; // no-warning +} + +void strcmp_constant_and_var_0() { + char *x = "123"; + if (strcmp(x, "123") != 0) + (void)*(char*)0; // no-warning +} + +void strcmp_constant_and_var_1() { + char *x = "123"; + if (strcmp("123", x) != 0) + (void)*(char*)0; // no-warning +} + +void strcmp_0() { + char *x = "123"; + char *y = "123"; + if (strcmp(x, y) != 0) + (void)*(char*)0; // no-warning +} + +void strcmp_1() { + char *x = "234"; + char *y = "123"; + if (strcmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcmp_2() { + char *x = "123"; + char *y = "234"; + if (strcmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcmp_null_0() { + char *x = NULL; + char *y = "123"; + strcmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strcmp_null_1() { + char *x = "123"; + char *y = NULL; + strcmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strcmp_diff_length_0() { + char *x = "12345"; + char *y = "234"; + if (strcmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcmp_diff_length_1() { + char *x = "123"; + char *y = "23456"; + if (strcmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcmp_diff_length_2() { + char *x = "12345"; + char *y = "123"; + if (strcmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcmp_diff_length_3() { + char *x = "123"; + char *y = "12345"; + if (strcmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcmp_embedded_null () { + if (strcmp("\0z", "\0y") != 0) + (void)*(char*)0; // no-warning +} + +void strcmp_unknown_arg (char *unknown) { + if (strcmp(unknown, unknown) != 0) + (void)*(char*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// strncmp() +//===----------------------------------------------------------------------=== + +#define strncmp BUILTIN(strncmp) +int strncmp(const char *s1, const char *s2, size_t n); + +void strncmp_constant0() { + if (strncmp("123", "123", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncmp_constant_and_var_0() { + char *x = "123"; + if (strncmp(x, "123", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncmp_constant_and_var_1() { + char *x = "123"; + if (strncmp("123", x, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncmp_0() { + char *x = "123"; + char *y = "123"; + if (strncmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncmp_1() { + char *x = "234"; + char *y = "123"; + if (strncmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +} + +void strncmp_2() { + char *x = "123"; + char *y = "234"; + if (strncmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncmp_null_0() { + char *x = NULL; + char *y = "123"; + strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strncmp_null_1() { + char *x = "123"; + char *y = NULL; + strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strncmp_diff_length_0() { + char *x = "12345"; + char *y = "234"; + if (strncmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_1() { + char *x = "123"; + char *y = "23456"; + if (strncmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_2() { + char *x = "12345"; + char *y = "123"; + if (strncmp(x, y, 5) != 1) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_3() { + char *x = "123"; + char *y = "12345"; + if (strncmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_4() { + char *x = "123"; + char *y = "12345"; + if (strncmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_5() { + char *x = "012"; + char *y = "12345"; + if (strncmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncmp_diff_length_6() { + char *x = "234"; + char *y = "12345"; + if (strncmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +} + +void strncmp_embedded_null () { + if (strncmp("ab\0zz", "ab\0yy", 4) != 0) + (void)*(char*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// strcasecmp() +//===----------------------------------------------------------------------=== + +#define strcasecmp BUILTIN(strcasecmp) +int strcasecmp(const char *s1, const char *s2); + +void strcasecmp_constant0() { + if (strcasecmp("abc", "Abc") != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_constant_and_var_0() { + char *x = "abc"; + if (strcasecmp(x, "Abc") != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_constant_and_var_1() { + char *x = "abc"; + if (strcasecmp("Abc", x) != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_0() { + char *x = "abc"; + char *y = "Abc"; + if (strcasecmp(x, y) != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_1() { + char *x = "Bcd"; + char *y = "abc"; + if (strcasecmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_2() { + char *x = "abc"; + char *y = "Bcd"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_null_0() { + char *x = NULL; + char *y = "123"; + strcasecmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strcasecmp_null_1() { + char *x = "123"; + char *y = NULL; + strcasecmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strcasecmp_diff_length_0() { + char *x = "abcde"; + char *y = "aBd"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_1() { + char *x = "abc"; + char *y = "aBdef"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_2() { + char *x = "aBcDe"; + char *y = "abc"; + if (strcasecmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_3() { + char *x = "aBc"; + char *y = "abcde"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_embedded_null () { + if (strcasecmp("ab\0zz", "ab\0yy") != 0) + (void)*(char*)0; // no-warning +} + +//===----------------------------------------------------------------------=== +// strncasecmp() +//===----------------------------------------------------------------------=== + +#define strncasecmp BUILTIN(strncasecmp) +int strncasecmp(const char *s1, const char *s2, size_t n); + +void strncasecmp_constant0() { + if (strncasecmp("abc", "Abc", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_constant_and_var_0() { + char *x = "abc"; + if (strncasecmp(x, "Abc", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_constant_and_var_1() { + char *x = "abc"; + if (strncasecmp("Abc", x, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_0() { + char *x = "abc"; + char *y = "Abc"; + if (strncasecmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_1() { + char *x = "Bcd"; + char *y = "abc"; + if (strncasecmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_2() { + char *x = "abc"; + char *y = "Bcd"; + if (strncasecmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_null_0() { + char *x = NULL; + char *y = "123"; + strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strncasecmp_null_1() { + char *x = "123"; + char *y = NULL; + strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}} +} + +void strncasecmp_diff_length_0() { + char *x = "abcde"; + char *y = "aBd"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_1() { + char *x = "abc"; + char *y = "aBdef"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_2() { + char *x = "aBcDe"; + char *y = "abc"; + if (strncasecmp(x, y, 5) != 1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_3() { + char *x = "aBc"; + char *y = "abcde"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_4() { + char *x = "abcde"; + char *y = "aBc"; + if (strncasecmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_5() { + char *x = "abcde"; + char *y = "aBd"; + if (strncasecmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_6() { + char *x = "aBDe"; + char *y = "abc"; + if (strncasecmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_embedded_null () { + if (strncasecmp("ab\0zz", "ab\0yy", 4) != 0) + (void)*(char*)0; // no-warning +} diff --git a/clang/test/Analysis/system-header-simulator-objc.h b/clang/test/Analysis/system-header-simulator-objc.h new file mode 100644 index 0000000..92d5899 --- /dev/null +++ b/clang/test/Analysis/system-header-simulator-objc.h @@ -0,0 +1,114 @@ +#pragma clang system_header + +typedef unsigned int UInt32; +typedef unsigned short UInt16; + +typedef signed long CFIndex; +typedef signed char BOOL; +typedef unsigned long NSUInteger; +typedef unsigned short unichar; +typedef UInt16 UniChar; + +enum { + NSASCIIStringEncoding = 1, + NSNEXTSTEPStringEncoding = 2, + NSJapaneseEUCStringEncoding = 3, + NSUTF8StringEncoding = 4, + NSISOLatin1StringEncoding = 5, + NSSymbolStringEncoding = 6, + NSNonLossyASCIIStringEncoding = 7, +}; +typedef const struct __CFString * CFStringRef; +typedef struct __CFString * CFMutableStringRef; +typedef NSUInteger NSStringEncoding; +typedef UInt32 CFStringEncoding; + +typedef const void * CFTypeRef; + +typedef const struct __CFAllocator * CFAllocatorRef; +extern const CFAllocatorRef kCFAllocatorDefault; +extern const CFAllocatorRef kCFAllocatorSystemDefault; +extern const CFAllocatorRef kCFAllocatorMalloc; +extern const CFAllocatorRef kCFAllocatorMallocZone; +extern const CFAllocatorRef kCFAllocatorNull; + +@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; +- (id)copy; +- (oneway void)release; +- (id)autorelease; +- (id)init; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; +@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; +@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +@interface NSObject (NSCoderMethods) +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +typedef struct { +} +NSFastEnumerationState; +@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end @class NSString, NSDictionary; +@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; +@end @interface NSNumber : NSValue - (char)charValue; +- (id)initWithInt:(int)value; +@end @class NSString; +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; +@end @interface NSArray (NSArrayCreation) + (id)array; +@end @interface NSAutoreleasePool : NSObject { +} +- (void)drain; +@end extern NSString * const NSBundleDidLoadNotification; +typedef double NSTimeInterval; +@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; +@end + +@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> +- (NSUInteger)length; +- (NSString *)stringByAppendingString:(NSString *)aString; +- ( const char *)UTF8String; +- (id)initWithUTF8String:(const char *)nullTerminatedCString; +- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer; +- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length; +- (id)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer; ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end @class NSString, NSURL, NSError; +@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; ++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; +- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; +@end + +typedef struct { +} +CFDictionaryKeyCallBacks; +extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks; +typedef struct { +} +CFDictionaryValueCallBacks; +extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; +typedef const struct __CFDictionary * CFDictionaryRef; +typedef struct __CFDictionary * CFMutableDictionaryRef; +extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); +void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *); + + +extern void CFRelease(CFTypeRef cf); + +extern CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocatorRef alloc, UniChar *chars, CFIndex numChars, CFIndex capacity, CFAllocatorRef externalCharactersAllocator); +extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); +extern void CFStringAppend(CFMutableStringRef theString, CFStringRef appendedString); diff --git a/clang/test/Analysis/system-header-simulator.h b/clang/test/Analysis/system-header-simulator.h new file mode 100644 index 0000000..6212131 --- /dev/null +++ b/clang/test/Analysis/system-header-simulator.h @@ -0,0 +1,38 @@ +#pragma clang system_header + +typedef struct _FILE FILE; +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +// Include a variant of standard streams that occur in the pre-processed file. +extern FILE *__stdinp; +extern FILE *__stdoutp; +extern FILE *__stderrp; + + +int fscanf(FILE *restrict, const char *restrict, ...); + +// Note, on some platforms errno macro gets replaced with a function call. +extern int errno; + +unsigned long strlen(const char *); + +char *strcpy(char *restrict, const char *restrict); + +typedef unsigned long __darwin_pthread_key_t; +typedef __darwin_pthread_key_t pthread_key_t; +int pthread_setspecific(pthread_key_t, const void *); + +typedef long long __int64_t; +typedef __int64_t __darwin_off_t; +typedef __darwin_off_t fpos_t; + +void setbuf(FILE * restrict, char * restrict); +int setvbuf(FILE * restrict, char * restrict, int, size_t); + +FILE *funopen(const void *, + int (*)(void *, char *, int), + int (*)(void *, const char *, int), + fpos_t (*)(void *, fpos_t, int), + int (*)(void *)); + diff --git a/clang/test/Analysis/taint-generic.c b/clang/test/Analysis/taint-generic.c new file mode 100644 index 0000000..b00372a --- /dev/null +++ b/clang/test/Analysis/taint-generic.c @@ -0,0 +1,185 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,core,experimental.security.ArrayBoundV2 -Wno-format-security -verify %s + +int scanf(const char *restrict format, ...); +int getchar(void); + +typedef struct _FILE FILE; +extern FILE *stdin; +int fscanf(FILE *restrict stream, const char *restrict format, ...); +int sprintf(char *str, const char *format, ...); +void setproctitle(const char *fmt, ...); +typedef __typeof(sizeof(int)) size_t; + +// Define string functions. Use builtin for some of them. They all default to +// the processing in the taint checker. +#define strcpy(dest, src) \ + ((__builtin_object_size(dest, 0) != -1ULL) \ + ? __builtin___strcpy_chk (dest, src, __builtin_object_size(dest, 1)) \ + : __inline_strcpy_chk(dest, src)) + +static char *__inline_strcpy_chk (char *dest, const char *src) { + return __builtin___strcpy_chk(dest, src, __builtin_object_size(dest, 1)); +} +char *stpcpy(char *restrict s1, const char *restrict s2); +char *strncpy( char * destination, const char * source, size_t num ); +char *strndup(const char *s, size_t n); +char *strncat(char *restrict s1, const char *restrict s2, size_t n); + +void *malloc(size_t); +void *calloc(size_t nmemb, size_t size); +void bcopy(void *s1, void *s2, size_t n); + +#define BUFSIZE 10 + +int Buffer[BUFSIZE]; +void bufferScanfDirect(void) +{ + int n; + scanf("%d", &n); + Buffer[n] = 1; // expected-warning {{Out of bound memory access }} +} + +void bufferScanfArithmetic1(int x) { + int n; + scanf("%d", &n); + int m = (n - 3); + Buffer[m] = 1; // expected-warning {{Out of bound memory access }} +} + +void bufferScanfArithmetic2(int x) { + int n; + scanf("%d", &n); + int m = 100 - (n + 3) * x; + Buffer[m] = 1; // expected-warning {{Out of bound memory access }} +} + +void bufferScanfAssignment(int x) { + int n; + scanf("%d", &n); + int m; + if (x > 0) { + m = n; + Buffer[m] = 1; // expected-warning {{Out of bound memory access }} + } +} + +void scanfArg() { + int t = 0; + scanf("%d", t); // expected-warning {{format specifies type 'int *' but the argument has type 'int'}} +} + +void bufferGetchar(int x) { + int m = getchar(); + Buffer[m] = 1; //expected-warning {{Out of bound memory access (index is tainted)}} +} + +void testUncontrolledFormatString(char **p) { + char s[80]; + fscanf(stdin, "%s", s); + char buf[128]; + sprintf(buf,s); // expected-warning {{Uncontrolled Format String}} + setproctitle(s, 3); // expected-warning {{Uncontrolled Format String}} + + // Test taint propagation through strcpy and family. + char scpy[80]; + strcpy(scpy, s); + sprintf(buf,scpy); // expected-warning {{Uncontrolled Format String}} + + stpcpy(*(++p), s); // this generates __inline. + setproctitle(*(p), 3); // expected-warning {{Uncontrolled Format String}} + + char spcpy[80]; + stpcpy(spcpy, s); + setproctitle(spcpy, 3); // expected-warning {{Uncontrolled Format String}} + + char *spcpyret; + spcpyret = stpcpy(spcpy, s); + setproctitle(spcpyret, 3); // expected-warning {{Uncontrolled Format String}} + + char sncpy[80]; + strncpy(sncpy, s, 20); + setproctitle(sncpy, 3); // expected-warning {{Uncontrolled Format String}} + + char *dup; + dup = strndup(s, 20); + setproctitle(dup, 3); // expected-warning {{Uncontrolled Format String}} + +} + +int system(const char *command); +void testTaintSystemCall() { + char buffer[156]; + char addr[128]; + scanf("%s", addr); + system(addr); // expected-warning {{Untrusted data is passed to a system call}} + + // Test that spintf transfers taint. + sprintf(buffer, "/bin/mail %s < /tmp/email", addr); + system(buffer); // expected-warning {{Untrusted data is passed to a system call}} +} + +void testTaintSystemCall2() { + // Test that snpintf transfers taint. + char buffern[156]; + char addr[128]; + scanf("%s", addr); + __builtin_snprintf(buffern, 10, "/bin/mail %s < /tmp/email", addr); + system(buffern); // expected-warning {{Untrusted data is passed to a system call}} +} + +void testTaintSystemCall3() { + char buffern2[156]; + int numt; + char addr[128]; + scanf("%s %d", addr, &numt); + __builtin_snprintf(buffern2, numt, "/bin/mail %s < /tmp/email", "abcd"); + system(buffern2); // expected-warning {{Untrusted data is passed to a system call}} +} + +void testTaintedBufferSize() { + size_t ts; + scanf("%zd", &ts); + + int *buf1 = (int*)malloc(ts*sizeof(int)); // expected-warning {{Untrusted data is used to specify the buffer size}} + char *dst = (char*)calloc(ts, sizeof(char)); //expected-warning {{Untrusted data is used to specify the buffer size}} + bcopy(buf1, dst, ts); // expected-warning {{Untrusted data is used to specify the buffer size}} + __builtin_memcpy(dst, buf1, (ts + 4)*sizeof(char)); // expected-warning {{Untrusted data is used to specify the buffer size}} + + // If both buffers are trusted, do not issue a warning. + char *dst2 = (char*)malloc(ts*sizeof(char)); // expected-warning {{Untrusted data is used to specify the buffer size}} + strncat(dst2, dst, ts); // no-warning +} + +#define AF_UNIX 1 /* local to host (pipes) */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_LOCAL AF_UNIX /* backward compatibility */ +#define SOCK_STREAM 1 +int socket(int, int, int); +size_t read(int, void *, size_t); +int execl(const char *, const char *, ...); + +void testSocket() { + int sock; + char buffer[100]; + + sock = socket(AF_INET, SOCK_STREAM, 0); + read(sock, buffer, 100); + execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}} + + sock = socket(AF_LOCAL, SOCK_STREAM, 0); + read(sock, buffer, 100); + execl(buffer, "filename", 0); // no-warning +} + +int testDivByZero() { + int x; + scanf("%d", &x); + return 5/x; // expected-warning {{Division by a tainted value, possibly zero}} +} + +// Zero-sized VLAs. +void testTaintedVLASize() { + int x; + scanf("%d", &x); + int vla[x]; // expected-warning{{Declared variable-length array (VLA) has tainted size}} +} diff --git a/clang/test/Analysis/taint-tester.c b/clang/test/Analysis/taint-tester.c new file mode 100644 index 0000000..3773335 --- /dev/null +++ b/clang/test/Analysis/taint-tester.c @@ -0,0 +1,204 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify + +#include <stdarg.h> + +int scanf(const char *restrict format, ...); +int getchar(void); +typedef __typeof(sizeof(int)) size_t; + +#define BUFSIZE 10 +int Buffer[BUFSIZE]; + +struct XYStruct { + int x; + int y; + char z; +}; + +void taintTracking(int x) { + int n; + int *addr = &Buffer[0]; + scanf("%d", &n); + addr += n;// expected-warning + {{tainted}} + *addr = n; // expected-warning + {{tainted}} + + double tdiv = n / 30; // expected-warning+ {{tainted}} + char *loc_cast = (char *) n; // expected-warning +{{tainted}} + char tinc = tdiv++; // expected-warning + {{tainted}} + int tincdec = (char)tinc--; // expected-warning+{{tainted}} + + // Tainted ptr arithmetic/array element address. + int tprtarithmetic1 = *(addr+1); // expected-warning + {{tainted}} + + // Dereference. + int *ptr; + scanf("%p", &ptr); + int ptrDeref = *ptr; // expected-warning + {{tainted}} + int _ptrDeref = ptrDeref + 13; // expected-warning + {{tainted}} + + // Pointer arithmetic + dereferencing. + // FIXME: We fail to propagate the taint here because RegionStore does not + // handle ElementRegions with symbolic indexes. + int addrDeref = *addr; // expected-warning + {{tainted}} + int _addrDeref = addrDeref; + + // Tainted struct address, casts. + struct XYStruct *xyPtr = 0; + scanf("%p", &xyPtr); + void *tXYStructPtr = xyPtr; // expected-warning + {{tainted}} + struct XYStruct *xyPtrCopy = tXYStructPtr; // expected-warning + {{tainted}} + int ptrtx = xyPtr->x;// expected-warning + {{tainted}} + int ptrty = xyPtr->y;// expected-warning + {{tainted}} + + // Taint on fields of a struct. + struct XYStruct xy = {2, 3, 11}; + scanf("%d", &xy.y); + scanf("%d", &xy.x); + int tx = xy.x; // expected-warning + {{tainted}} + int ty = xy.y; // FIXME: This should be tainted as well. + char ntz = xy.z;// no warning + // Now, scanf scans both. + scanf("%d %d", &xy.y, &xy.x); + int ttx = xy.x; // expected-warning + {{tainted}} + int tty = xy.y; // expected-warning + {{tainted}} +} + +void BitwiseOp(int in, char inn) { + // Taint on bitwise operations, integer to integer cast. + int m; + int x = 0; + scanf("%d", &x); + int y = (in << (x << in)) * 5;// expected-warning + {{tainted}} + // The next line tests integer to integer cast. + int z = y & inn; // expected-warning + {{tainted}} + if (y == 5) // expected-warning + {{tainted}} + m = z | z;// expected-warning + {{tainted}} + else + m = inn; + int mm = m; // expected-warning + {{tainted}} +} + +// Test getenv. +char *getenv(const char *name); +void getenvTest(char *home) { + home = getenv("HOME"); // expected-warning + {{tainted}} + if (home != 0) { // expected-warning + {{tainted}} + char d = home[0]; // expected-warning + {{tainted}} + } +} + +typedef struct _FILE FILE; +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +int fscanf(FILE *restrict stream, const char *restrict format, ...); +int fprintf(FILE *stream, const char *format, ...); +int fclose(FILE *stream); +FILE *fopen(const char *path, const char *mode); + +int fscanfTest(void) { + FILE *fp; + char s[80]; + int t; + + // Check if stdin is treated as tainted. + fscanf(stdin, "%s %d", s, &t); + // Note, here, s is not tainted, but the data s points to is tainted. + char *ts = s; + char tss = s[0]; // expected-warning + {{tainted}} + int tt = t; // expected-warning + {{tainted}} + if((fp=fopen("test", "w")) == 0) // expected-warning + {{tainted}} + return 1; + fprintf(fp, "%s %d", s, t); // expected-warning + {{tainted}} + fclose(fp); // expected-warning + {{tainted}} + + // Test fscanf and fopen. + if((fp=fopen("test","r")) == 0) // expected-warning + {{tainted}} + return 1; + fscanf(fp, "%s%d", s, &t); // expected-warning + {{tainted}} + fprintf(stdout, "%s %d", s, t); // expected-warning + {{tainted}} + return 0; +} + +// Check if we propagate taint from stdin when it's used in an assignment. +void stdinTest1() { + int i; + fscanf(stdin, "%d", &i); + int j = i; // expected-warning + {{tainted}} +} +void stdinTest2(FILE *pIn) { + FILE *p = stdin; + FILE *pp = p; + int ii; + + fscanf(pp, "%d", &ii); + int jj = ii;// expected-warning + {{tainted}} + + fscanf(p, "%d", &ii); + int jj2 = ii;// expected-warning + {{tainted}} + + ii = 3; + int jj3 = ii;// no warning + + p = pIn; + fscanf(p, "%d", &ii); + int jj4 = ii;// no warning +} + +void stdinTest3() { + FILE **ppp = &stdin; + int iii; + fscanf(*ppp, "%d", &iii); + int jjj = iii;// expected-warning + {{tainted}} +} + +// Test that stdin does not get invalidated by calls. +void foo(); +void stdinTest4() { + int i; + fscanf(stdin, "%d", &i); + foo(); + int j = i; // expected-warning + {{tainted}} +} + +int getw(FILE *); +void getwTest() { + int i = getw(stdin); // expected-warning + {{tainted}} +} + +typedef long ssize_t; +ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict); +int printf(const char * __restrict, ...); +void free(void *ptr); +void getlineTest(void) { + FILE *fp; + char *line = 0; + size_t len = 0; + ssize_t read; + while ((read = getline(&line, &len, stdin)) != -1) { + printf("%s", line); // expected-warning + {{tainted}} + } + free(line); // expected-warning + {{tainted}} +} + +// Test propagation functions - the ones that propagate taint from arguments to +// return value, ptr arguments. + +int atoi(const char *nptr); +long atol(const char *nptr); +long long atoll(const char *nptr); + +void atoiTest() { + char s[80]; + scanf("%s", s); + int d = atoi(s); // expected-warning + {{tainted}} + int td = d; // expected-warning + {{tainted}} + + long l = atol(s); // expected-warning + {{tainted}} + int tl = l; // expected-warning + {{tainted}} + + long long ll = atoll(s); // expected-warning + {{tainted}} + int tll = ll; // expected-warning + {{tainted}} + +} + diff --git a/clang/test/Analysis/taint-tester.cpp b/clang/test/Analysis/taint-tester.cpp new file mode 100644 index 0000000..679fbc2 --- /dev/null +++ b/clang/test/Analysis/taint-tester.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify + +typedef struct _FILE FILE; +typedef __typeof(sizeof(int)) size_t; +extern FILE *stdin; +typedef long ssize_t; +ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict); +int printf(const char * __restrict, ...); +void free(void *ptr); + +struct GetLineTestStruct { + ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict); +}; + +void getlineTest(void) { + FILE *fp; + char *line = 0; + size_t len = 0; + ssize_t read; + struct GetLineTestStruct T; + + while ((read = T.getline(&line, &len, stdin)) != -1) { + printf("%s", line); // no warning + } + free(line); +} diff --git a/clang/test/Analysis/taint-tester.m b/clang/test/Analysis/taint-tester.m new file mode 100644 index 0000000..ae55c66 --- /dev/null +++ b/clang/test/Analysis/taint-tester.m @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify + +#import <stdarg.h> + +@interface NSString +- (NSString *)stringByAppendingString:(NSString *)aString; +@end +extern void NSLog (NSString *format, ...); +extern void NSLogv(NSString *format, va_list args); + +void TestLog (NSString *format, ...); +void TestLog (NSString *format, ...) { + va_list ap; + va_start(ap, format); + NSString *string = @"AAA: "; + + NSLogv([string stringByAppendingString:format], ap); + + va_end(ap); +}
\ No newline at end of file diff --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp new file mode 100644 index 0000000..53ab211 --- /dev/null +++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -0,0 +1,767 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors -cfg-add-initializers %s 2>&1 | FileCheck %s +// XPASS: * + +class A { +public: + A() {} + ~A() {} + + static A make() { return A(); } + + operator bool() { return false; } + operator int() { return 0; } +}; + +class B { +public: + B() {} + ~B() {} + + operator bool() { return true; } + operator int() { return 1; } + operator A() { return A(); } +}; + +void foo(int); +void foo(bool); +void foo(const A&); + +void test_binary() { + int a = int(A()) + int(B()); + foo(int(A()) + int(B())); + int b; +} + +void test_and() { + bool a = A() && B(); + foo(A() && B()); + int b; +} + +void test_or() { + bool a = A() || B(); + foo(A() || B()); + int b; +} + +void test_cond() { + A a = B() ? A() : A(B()); + if (B()) { foo(0); } else { foo(0); } + int b; +} + +void test_cond_cref() { + const A& a = B() ? A() : A(B()); + foo(B() ? A() : A(B())); + int b; +} + +void test_cond_implicit() { + A a = A() ?: A(); + int b; +} + +void test_cond_implicit_cref() { + const A& a = A() ?: A(); + foo(A() ?: A()); + int b; +} + +void test_copy_init() { + A a = A(); + int b; +} + +void test_cref_init() { + const A& a = A(); + foo(A()); + int b; +} + +void test_call_copy_init() { + A a = A::make(); + int b; +} + +void test_call_cref_init() { + const A& a = A::make(); + foo(A::make()); + int b; +} + +void test_assign() { + int a; + a = A(); + int b; +} + +class TestCtorInits { + int a; + int b; +public: + TestCtorInits(); +}; + +TestCtorInits::TestCtorInits() + : a(int(A()) + int(B())) + , b() {} + +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 + +// CHECK: [B1] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B1.1] (BindTemporary) +// CHECK: 3: [B1.2].operator int +// CHECK: 4: [B1.3]() +// CHECK: 5: [B1.4] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 6: int([B1.5]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 7: B() (CXXConstructExpr, class B) +// CHECK: 8: [B1.7] (BindTemporary) +// CHECK: 9: [B1.8].operator int +// CHECK: 10: [B1.9]() +// CHECK: 11: [B1.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 12: int([B1.11]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 13: [B1.6] + [B1.12] +// CHECK: 14: int a = int(A().operator int()) + int(B().operator int()); +// CHECK: 15: ~B() (Temporary object destructor) +// CHECK: 16: ~A() (Temporary object destructor) +// CHECK: 17: A() (CXXConstructExpr, class A) +// CHECK: 18: [B1.17] (BindTemporary) +// CHECK: 19: [B1.18].operator int +// CHECK: 20: [B1.19]() +// CHECK: 21: [B1.20] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 22: int([B1.21]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 23: B() (CXXConstructExpr, class B) +// CHECK: 24: [B1.23] (BindTemporary) +// CHECK: 25: [B1.24].operator int +// CHECK: 26: [B1.25]() +// CHECK: 27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 29: [B1.22] + [B1.28] +// CHECK: 30: foo +// CHECK: 31: [B1.30] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int)) +// CHECK: 32: [B1.31]([B1.29]) +// CHECK: 33: ~B() (Temporary object destructor) +// CHECK: 34: ~A() (Temporary object destructor) +// CHECK: 35: int b; +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B10 (ENTRY)] +// CHECK: Succs (1): B8 +// CHECK: [B1] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: int b; +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: Preds (1): B3 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: [B4.6] && [B5.5] +// CHECK: 2: foo +// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool)) +// CHECK: 4: [B3.3]([B3.1]) +// CHECK: T: [B4.6] && ... +// CHECK: Preds (2): B5 B4 +// CHECK: Succs (2): B2 B1 +// CHECK: [B4] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: A() (CXXConstructExpr, class A) +// CHECK: 3: [B4.2] (BindTemporary) +// CHECK: 4: [B4.3].operator _Bool +// CHECK: 5: [B4.4]() +// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B4.6] && ... +// CHECK: Preds (2): B6 B7 +// CHECK: Succs (2): B5 B3 +// CHECK: [B5] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B5.1] (BindTemporary) +// CHECK: 3: [B5.2].operator _Bool +// CHECK: 4: [B5.3]() +// CHECK: 5: [B5.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B3 +// CHECK: [B6] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: [B8.5] && [B9.5] +// CHECK: 2: bool a = A().operator _Bool() && B().operator _Bool(); +// CHECK: T: [B8.5] && ... +// CHECK: Preds (2): B9 B8 +// CHECK: Succs (2): B6 B4 +// CHECK: [B8] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B8.1] (BindTemporary) +// CHECK: 3: [B8.2].operator _Bool +// CHECK: 4: [B8.3]() +// CHECK: 5: [B8.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B8.5] && ... +// CHECK: Preds (1): B10 +// CHECK: Succs (2): B9 B7 +// CHECK: [B9] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B9.1] (BindTemporary) +// CHECK: 3: [B9.2].operator _Bool +// CHECK: 4: [B9.3]() +// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B7 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B10 (ENTRY)] +// CHECK: Succs (1): B8 +// CHECK: [B1] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: int b; +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: Preds (1): B3 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: [B4.6] || [B5.5] +// CHECK: 2: foo +// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool)) +// CHECK: 4: [B3.3]([B3.1]) +// CHECK: T: [B4.6] || ... +// CHECK: Preds (2): B5 B4 +// CHECK: Succs (2): B1 B2 +// CHECK: [B4] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: A() (CXXConstructExpr, class A) +// CHECK: 3: [B4.2] (BindTemporary) +// CHECK: 4: [B4.3].operator _Bool +// CHECK: 5: [B4.4]() +// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B4.6] || ... +// CHECK: Preds (2): B6 B7 +// CHECK: Succs (2): B3 B5 +// CHECK: [B5] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B5.1] (BindTemporary) +// CHECK: 3: [B5.2].operator _Bool +// CHECK: 4: [B5.3]() +// CHECK: 5: [B5.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B3 +// CHECK: [B6] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: [B8.5] || [B9.5] +// CHECK: 2: bool a = A().operator _Bool() || B().operator _Bool(); +// CHECK: T: [B8.5] || ... +// CHECK: Preds (2): B9 B8 +// CHECK: Succs (2): B4 B6 +// CHECK: [B8] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B8.1] (BindTemporary) +// CHECK: 3: [B8.2].operator _Bool +// CHECK: 4: [B8.3]() +// CHECK: 5: [B8.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B8.5] || ... +// CHECK: Preds (1): B10 +// CHECK: Succs (2): B7 B9 +// CHECK: [B9] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B9.1] (BindTemporary) +// CHECK: 3: [B9.2].operator _Bool +// CHECK: 4: [B9.3]() +// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: Preds (1): B8 +// CHECK: Succs (1): B7 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B11 (ENTRY)] +// CHECK: Succs (1): B10 +// CHECK: [B1] +// CHECK: 1: int b; +// CHECK: 2: [B7.5].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: 0 +// CHECK: 2: foo +// CHECK: 3: [B2.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int)) +// CHECK: 4: [B2.3]([B2.1]) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: 0 +// CHECK: 2: foo +// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int)) +// CHECK: 4: [B3.3]([B3.1]) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: 2: B() (CXXConstructExpr, class B) +// CHECK: 3: [B4.2] (BindTemporary) +// CHECK: 4: [B4.3].operator _Bool +// CHECK: 5: [B4.4]() +// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: 7: ~B() (Temporary object destructor) +// CHECK: T: if [B4.6] +// CHECK: Preds (2): B5 B6 +// CHECK: Succs (2): B3 B2 +// CHECK: [B5] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B6] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: 3: ~A() (Temporary object destructor) +// CHECK: 4: ~B() (Temporary object destructor) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: [B10.5] ? [B8.6] : [B9.15] +// CHECK: 2: [B7.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B7.2] +// CHECK: 4: [B7.3] (CXXConstructExpr, class A) +// CHECK: 5: A a = B().operator _Bool() ? A() : A(B().operator A()); +// CHECK: T: [B10.5] ? ... : ... +// CHECK: Preds (2): B8 B9 +// CHECK: Succs (2): B5 B6 +// CHECK: [B8] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B8.1] (BindTemporary) +// CHECK: 3: [B8.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B8.3] +// CHECK: 5: [B8.4] (CXXConstructExpr, class A) +// CHECK: 6: [B8.5] (BindTemporary) +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B7 +// CHECK: [B9] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B9.1] (BindTemporary) +// CHECK: 3: [B9.2].operator A +// CHECK: 4: [B9.3]() +// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, class A) +// CHECK: 6: [B9.5] (BindTemporary) +// CHECK: 7: [B9.6] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 8: [B9.7] +// CHECK: 9: [B9.8] (CXXConstructExpr, class A) +// CHECK: 10: [B9.9] (BindTemporary) +// CHECK: 11: A([B9.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) +// CHECK: 12: [B9.11] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 13: [B9.12] +// CHECK: 14: [B9.13] (CXXConstructExpr, class A) +// CHECK: 15: [B9.14] (BindTemporary) +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B7 +// CHECK: [B10] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B10.1] (BindTemporary) +// CHECK: 3: [B10.2].operator _Bool +// CHECK: 4: [B10.3]() +// CHECK: 5: [B10.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B10.5] ? ... : ... +// CHECK: Preds (1): B11 +// CHECK: Succs (2): B8 B9 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B14 (ENTRY)] +// CHECK: Succs (1): B13 +// CHECK: [B1] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: 2: int b; +// CHECK: 3: [B10.4].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: 3: ~A() (Temporary object destructor) +// CHECK: 4: ~B() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: [B7.6] ? [B5.6] : [B6.15] +// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B4.2] +// CHECK: 4: foo +// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) +// CHECK: 6: [B4.5]([B4.3]) +// CHECK: T: [B7.6] ? ... : ... +// CHECK: Preds (2): B5 B6 +// CHECK: Succs (2): B2 B3 +// CHECK: [B5] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B5.1] (BindTemporary) +// CHECK: 3: [B5.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B5.3] +// CHECK: 5: [B5.4] (CXXConstructExpr, class A) +// CHECK: 6: [B5.5] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B6] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B6.1] (BindTemporary) +// CHECK: 3: [B6.2].operator A +// CHECK: 4: [B6.3]() +// CHECK: 5: [B6.4] (ImplicitCastExpr, UserDefinedConversion, class A) +// CHECK: 6: [B6.5] (BindTemporary) +// CHECK: 7: [B6.6] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 8: [B6.7] +// CHECK: 9: [B6.8] (CXXConstructExpr, class A) +// CHECK: 10: [B6.9] (BindTemporary) +// CHECK: 11: A([B6.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) +// CHECK: 12: [B6.11] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 13: [B6.12] +// CHECK: 14: [B6.13] (CXXConstructExpr, class A) +// CHECK: 15: [B6.14] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: ~B() (Temporary object destructor) +// CHECK: 2: B() (CXXConstructExpr, class B) +// CHECK: 3: [B7.2] (BindTemporary) +// CHECK: 4: [B7.3].operator _Bool +// CHECK: 5: [B7.4]() +// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B7.6] ? ... : ... +// CHECK: Preds (2): B8 B9 +// CHECK: Succs (2): B5 B6 +// CHECK: [B8] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B7 +// CHECK: [B9] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: 3: ~B() (Temporary object destructor) +// CHECK: Preds (1): B10 +// CHECK: Succs (1): B7 +// CHECK: [B10] +// CHECK: 1: [B13.5] ? [B11.6] : [B12.15] +// CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B10.2] +// CHECK: 4: const A &a = B().operator _Bool() ? A() : A(B().operator A()); +// CHECK: T: [B13.5] ? ... : ... +// CHECK: Preds (2): B11 B12 +// CHECK: Succs (2): B8 B9 +// CHECK: [B11] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B11.1] (BindTemporary) +// CHECK: 3: [B11.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B11.3] +// CHECK: 5: [B11.4] (CXXConstructExpr, class A) +// CHECK: 6: [B11.5] (BindTemporary) +// CHECK: Preds (1): B13 +// CHECK: Succs (1): B10 +// CHECK: [B12] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B12.1] (BindTemporary) +// CHECK: 3: [B12.2].operator A +// CHECK: 4: [B12.3]() +// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, class A) +// CHECK: 6: [B12.5] (BindTemporary) +// CHECK: 7: [B12.6] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 8: [B12.7] +// CHECK: 9: [B12.8] (CXXConstructExpr, class A) +// CHECK: 10: [B12.9] (BindTemporary) +// CHECK: 11: A([B12.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) +// CHECK: 12: [B12.11] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 13: [B12.12] +// CHECK: 14: [B12.13] (CXXConstructExpr, class A) +// CHECK: 15: [B12.14] (BindTemporary) +// CHECK: Preds (1): B13 +// CHECK: Succs (1): B10 +// CHECK: [B13] +// CHECK: 1: B() (CXXConstructExpr, class B) +// CHECK: 2: [B13.1] (BindTemporary) +// CHECK: 3: [B13.2].operator _Bool +// CHECK: 4: [B13.3]() +// CHECK: 5: [B13.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B13.5] ? ... : ... +// CHECK: Preds (1): B14 +// CHECK: Succs (2): B11 B12 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B8 (ENTRY)] +// CHECK: Succs (1): B7 +// CHECK: [B1] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: int b; +// CHECK: 3: [B4.5].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: [B7.2] ?: [B6.6] +// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B4.2] +// CHECK: 4: [B4.3] (CXXConstructExpr, class A) +// CHECK: 5: A a = A() ?: A(); +// CHECK: T: [B7.5] ? ... : ... +// CHECK: Preds (2): B5 B6 +// CHECK: Succs (2): B2 B3 +// CHECK: [B5] +// CHECK: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 2: [B5.1] +// CHECK: 3: [B5.2] (CXXConstructExpr, class A) +// CHECK: 4: [B5.3] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B6] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B6.1] (BindTemporary) +// CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B6.3] +// CHECK: 5: [B6.4] (CXXConstructExpr, class A) +// CHECK: 6: [B6.5] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B7.1] (BindTemporary) +// CHECK: 3: [B7.2].operator _Bool +// CHECK: 4: [B7.3]() +// CHECK: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B7.5] ? ... : ... +// CHECK: Preds (1): B8 +// CHECK: Succs (2): B5 B6 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B13 (ENTRY)] +// CHECK: Succs (1): B12 +// CHECK: [B1] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: int b; +// CHECK: 3: [B9.4].~A() (Implicit destructor) +// CHECK: Preds (2): B2 B3 +// CHECK: Succs (1): B0 +// CHECK: [B2] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B3] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: ~A() (Temporary object destructor) +// CHECK: Preds (1): B4 +// CHECK: Succs (1): B1 +// CHECK: [B4] +// CHECK: 1: [B7.3] ?: [B6.6] +// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B4.2] +// CHECK: 4: foo +// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) +// CHECK: 6: [B4.5]([B4.3]) +// CHECK: T: [B7.6] ? ... : ... +// CHECK: Preds (2): B5 B6 +// CHECK: Succs (2): B2 B3 +// CHECK: [B5] +// CHECK: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 2: [B5.1] +// CHECK: 3: [B5.2] (CXXConstructExpr, class A) +// CHECK: 4: [B5.3] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B6] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B6.1] (BindTemporary) +// CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B6.3] +// CHECK: 5: [B6.4] (CXXConstructExpr, class A) +// CHECK: 6: [B6.5] (BindTemporary) +// CHECK: Preds (1): B7 +// CHECK: Succs (1): B4 +// CHECK: [B7] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: 2: A() (CXXConstructExpr, class A) +// CHECK: 3: [B7.2] (BindTemporary) +// CHECK: 4: [B7.3].operator _Bool +// CHECK: 5: [B7.4]() +// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B7.6] ? ... : ... +// CHECK: Preds (2): B9 B8 +// CHECK: Succs (2): B5 B6 +// CHECK: [B8] +// CHECK: 1: ~A() (Temporary object destructor) +// CHECK: Preds (1): B9 +// CHECK: Succs (1): B7 +// CHECK: [B9] +// CHECK: 1: [B12.2] ?: [B11.6] +// CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 3: [B9.2] +// CHECK: 4: const A &a = A() ?: A(); +// CHECK: T: [B12.5] ? ... : ... +// CHECK: Preds (2): B10 B11 +// CHECK: Succs (2): B7 B8 +// CHECK: [B10] +// CHECK: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 2: [B10.1] +// CHECK: 3: [B10.2] (CXXConstructExpr, class A) +// CHECK: 4: [B10.3] (BindTemporary) +// CHECK: Preds (1): B12 +// CHECK: Succs (1): B9 +// CHECK: [B11] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B11.1] (BindTemporary) +// CHECK: 3: [B11.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B11.3] +// CHECK: 5: [B11.4] (CXXConstructExpr, class A) +// CHECK: 6: [B11.5] (BindTemporary) +// CHECK: Preds (1): B12 +// CHECK: Succs (1): B9 +// CHECK: [B12] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B12.1] (BindTemporary) +// CHECK: 3: [B12.2].operator _Bool +// CHECK: 4: [B12.3]() +// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: [B12.5] ? ... : ... +// CHECK: Preds (1): B13 +// CHECK: Succs (2): B10 B11 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B1.1] (BindTemporary) +// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B1.3] +// CHECK: 5: [B1.4] (CXXConstructExpr, class A) +// CHECK: 6: A a = A(); +// CHECK: 7: ~A() (Temporary object destructor) +// CHECK: 8: int b; +// CHECK: 9: [B1.6].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B1.1] (BindTemporary) +// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 4: [B1.3] +// CHECK: 5: const A &a = A(); +// CHECK: 6: A() (CXXConstructExpr, class A) +// CHECK: 7: [B1.6] (BindTemporary) +// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 9: [B1.8] +// CHECK: 10: foo +// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) +// CHECK: 12: [B1.11]([B1.9]) +// CHECK: 13: ~A() (Temporary object destructor) +// CHECK: 14: int b; +// CHECK: 15: [B1.5].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: A::make +// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void)) +// CHECK: 3: [B1.2]() +// CHECK: 4: [B1.3] (BindTemporary) +// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 6: [B1.5] +// CHECK: 7: [B1.6] (CXXConstructExpr, class A) +// CHECK: 8: A a = A::make(); +// CHECK: 9: ~A() (Temporary object destructor) +// CHECK: 10: int b; +// CHECK: 11: [B1.8].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: A::make +// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void)) +// CHECK: 3: [B1.2]() +// CHECK: 4: [B1.3] (BindTemporary) +// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 6: [B1.5] +// CHECK: 7: const A &a = A::make(); +// CHECK: 8: A::make +// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void)) +// CHECK: 10: [B1.9]() +// CHECK: 11: [B1.10] (BindTemporary) +// CHECK: 12: [B1.11] (ImplicitCastExpr, NoOp, const class A) +// CHECK: 13: [B1.12] +// CHECK: 14: foo +// CHECK: 15: [B1.14] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) +// CHECK: 16: [B1.15]([B1.13]) +// CHECK: 17: ~A() (Temporary object destructor) +// CHECK: 18: int b; +// CHECK: 19: [B1.7].~A() (Implicit destructor) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: int a; +// CHECK: 2: A() (CXXConstructExpr, class A) +// CHECK: 3: [B1.2] (BindTemporary) +// CHECK: 4: [B1.3].operator int +// CHECK: 5: [B1.4]() +// CHECK: 6: [B1.5] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 7: a +// CHECK: 8: [B1.7] = [B1.6] +// CHECK: 9: ~A() (Temporary object destructor) +// CHECK: 10: int b; +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 +// CHECK: [B2 (ENTRY)] +// CHECK: Succs (1): B1 +// CHECK: [B1] +// CHECK: 1: A() (CXXConstructExpr, class A) +// CHECK: 2: [B1.1] (BindTemporary) +// CHECK: 3: [B1.2].operator int +// CHECK: 4: [B1.3]() +// CHECK: 5: [B1.4] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 6: int([B1.5]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 7: B() (CXXConstructExpr, class B) +// CHECK: 8: [B1.7] (BindTemporary) +// CHECK: 9: [B1.8].operator int +// CHECK: 10: [B1.9]() +// CHECK: 11: [B1.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 12: int([B1.11]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 13: [B1.6] + [B1.12] +// CHECK: 14: a([B1.13]) (Member initializer) +// CHECK: 15: ~B() (Temporary object destructor) +// CHECK: 16: ~A() (Temporary object destructor) +// CHECK: 17: /*implicit*/int() +// CHECK: 18: b([B1.17]) (Member initializer) +// CHECK: Preds (1): B2 +// CHECK: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK: Preds (1): B1 + diff --git a/clang/test/Analysis/undef-buffers.c b/clang/test/Analysis/undef-buffers.c new file mode 100644 index 0000000..cfdd7f4 --- /dev/null +++ b/clang/test/Analysis/undef-buffers.c @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix,core.uninitialized -analyzer-store=region -verify %s +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +char stackBased1 () { + char buf[2]; + buf[0] = 'a'; + return buf[1]; // expected-warning{{Undefined}} +} + +char stackBased2 () { + char buf[2]; + buf[1] = 'a'; + return buf[0]; // expected-warning{{Undefined}} +} + +// Exercise the conditional visitor. Radar://10105448 +char stackBased3 (int *x) { + char buf[2]; + int *y; + buf[0] = 'a'; + if (!(y = x)) { + return buf[1]; // expected-warning{{Undefined}} + } + return buf[0]; +} + +char heapBased1 () { + char *buf = malloc(2); + buf[0] = 'a'; + char result = buf[1]; // expected-warning{{undefined}} + free(buf); + return result; +} + +char heapBased2 () { + char *buf = malloc(2); + buf[1] = 'a'; + char result = buf[0]; // expected-warning{{undefined}} + free(buf); + return result; +} diff --git a/clang/test/Analysis/uninit-msg-expr.m b/clang/test/Analysis/uninit-msg-expr.m new file mode 100644 index 0000000..19fdf61 --- /dev/null +++ b/clang/test/Analysis/uninit-msg-expr.m @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -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 <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 <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +- (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 {{Argument in message expression is an uninitialized value}} +} diff --git a/clang/test/Analysis/uninit-ps-rdar6145427.m b/clang/test/Analysis/uninit-ps-rdar6145427.m new file mode 100644 index 0000000..c18116f --- /dev/null +++ b/clang/test/Analysis/uninit-ps-rdar6145427.m @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=region %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 <NSObject> {} ++ (id)alloc; +- (id)init; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSValue : NSObject <NSCopying, NSCoding> - (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: <rdar://problem/6145427> + +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/clang/test/Analysis/uninit-vals-ps-region.m b/clang/test/Analysis/uninit-vals-ps-region.m new file mode 100644 index 0000000..d613c71 --- /dev/null +++ b/clang/test/Analysis/uninit-vals-ps-region.m @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.deadcode.IdempotentOperations -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 +} + + +// Test uninitialized value due to part of the structure being uninitialized. +struct TestUninit { int x; int y; }; +struct TestUninit test_uninit_aux(); +void test_unit_aux2(int); +void test_uninit_pos() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2 = test_uninit_aux(); + int z; + v1.y = z; // expected-warning{{Assigned value is garbage or undefined}} + test_unit_aux2(v2.x + v1.y); +} +void test_uninit_pos_2() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2; + test_unit_aux2(v2.x + v1.y); // expected-warning{{The left operand of '+' is a garbage value}} +} +void test_uninit_pos_3() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2; + test_unit_aux2(v1.y + v2.x); // expected-warning{{The right operand of '+' is a garbage value}} +} + +void test_uninit_neg() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2 = test_uninit_aux(); + test_unit_aux2(v2.x + v1.y); // expected-warning{{The right operand to '+' is always 0}} +} + +extern void test_uninit_struct_arg_aux(struct TestUninit arg); +void test_uninit_struct_arg() { + struct TestUninit x; + test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} +} + +@interface Foo +- (void) passVal:(struct TestUninit)arg; +@end +void testFoo(Foo *o) { + struct TestUninit x; + [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} +} + +// Test case from <rdar://problem/7780304>. That shows an uninitialized value +// being used in the LHS of a compound assignment. +void rdar_7780304() { + typedef struct s_r7780304 { int x; } s_r7780304; + s_r7780304 b; + b.x |= 1; // expected-warning{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}} +} + + +// The flip side of PR10163 -- float arrays that are actually uninitialized +// (The main test is in uninit-vals.m) +void test_PR10163(float); +void PR10163 (void) { + float x[2]; + test_PR10163(x[1]); // expected-warning{{uninitialized value}} +} + diff --git a/clang/test/Analysis/uninit-vals-ps.c b/clang/test/Analysis/uninit-vals-ps.c new file mode 100644 index 0000000..f301157 --- /dev/null +++ b/clang/test/Analysis/uninit-vals-ps.c @@ -0,0 +1,124 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -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{{Function call argument is an uninitialized value}} +} + +int f2() { + + int x; + + if (x+1) // expected-warning{{The left operand of '+' is a garbage value}} + return 1; + + return 2; +} + +int f2_b() { + int x; + + return ((1+x)+2+((x))) + 1 ? 1 : 2; // expected-warning{{The right operand of '+' is a garbage value}} +} + +int f3(void) { + int i; + int *p = &i; + if (*p > 0) // expected-warning{{The left operand of '>' is a garbage 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{{Undefined or garbage value returned to caller}} +} + +// <rdar://problem/6451816> +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 +} + +// PR 4630 - false warning with nonnull attribute +// This false positive (due to a regression) caused the analyzer to falsely +// flag a "return of uninitialized value" warning in the first branch due to +// the nonnull attribute. +void pr_4630_aux(char *x, int *y) __attribute__ ((nonnull (1))); +void pr_4630_aux_2(char *x, int *y); +int pr_4630(char *a, int y) { + int x; + if (y) { + pr_4630_aux(a, &x); + return x; // no-warning + } + else { + pr_4630_aux_2(a, &x); + return x; // no-warning + } +} + +// PR 4631 - False positive with union initializer +// Previously the analyzer didn't examine the compound initializers of unions, +// resulting in some false positives for initializers with side-effects. +union u_4631 { int a; }; +struct s_4631 { int a; }; +int pr4631_f2(int *p); +int pr4631_f3(void *q); +int pr4631_f1(void) +{ + int x; + union u_4631 m = { pr4631_f2(&x) }; + pr4631_f3(&m); // tell analyzer that we use m + return x; // no-warning +} +int pr4631_f1_b(void) +{ + int x; + struct s_4631 m = { pr4631_f2(&x) }; + pr4631_f3(&m); // tell analyzer that we use m + return x; // no-warning +} + diff --git a/clang/test/Analysis/uninit-vals.m b/clang/test/Analysis/uninit-vals.m new file mode 100644 index 0000000..4ba26f5 --- /dev/null +++ b/clang/test/Analysis/uninit-vals.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -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; +} + + +// PR10163 -- don't warn for default-initialized float arrays. +// (An additional test is in uninit-vals-ps-region.m) +void test_PR10163(float); +void PR10163 (void) { + float x[2] = {0}; + test_PR10163(x[1]); // no-warning +} diff --git a/clang/test/Analysis/unions-region.m b/clang/test/Analysis/unions-region.m new file mode 100644 index 0000000..1a71684 --- /dev/null +++ b/clang/test/Analysis/unions-region.m @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range %s -verify + +//===-- unions-region.m ---------------------------------------------------===// +// +// This file tests the analyzer's reasoning about unions. +// +//===----------------------------------------------------------------------===// + +// [testA] When using RegionStore, this test case previously had a +// false positive of a 'pass-by-value argument is uninitialized' +// warning at the call to 'testA_aux' and 'testA_aux_2'. +union u_testA { + unsigned i; + float f; +}; + +float testA(float f) { + int testA_aux(unsigned x); + int testA_aux_2(union u_testA z); + + union u_testA swap; + swap.f = f; + + if (testA_aux(swap.i)) // no-warning + swap.i = ((swap.i & 0xffff0000) >> 16) | ((swap.i & 0x0000fffff) << 16); + + testA_aux_2(swap); // no-warning + + return swap.f; +} + +// [testB] When using RegionStore, this test case previously had a +// false positive of a 'pass-by-value argument is uninitialized' +// warning at the call to 'testB_aux'. +void testB(int i) { + void testB_aux(short z); + union { short x[2]; unsigned y; } val; + val.y = 10; + testB_aux(val.x[1]); // no-warning +} + diff --git a/clang/test/Analysis/unix-fns.c b/clang/test/Analysis/unix-fns.c new file mode 100644 index 0000000..ec62098 --- /dev/null +++ b/clang/test/Analysis/unix-fns.c @@ -0,0 +1,138 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=region -fblocks -verify + +struct _opaque_pthread_once_t { + long __sig; + char __opaque[8]; +}; +typedef struct _opaque_pthread_once_t __darwin_pthread_once_t; +typedef __darwin_pthread_once_t pthread_once_t; +int pthread_once(pthread_once_t *, void (*)(void)); +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +void *calloc(size_t, size_t); +void *malloc(size_t); +void *realloc(void *, size_t); +void *alloca(size_t); +void *valloc(size_t); + +typedef void (^dispatch_block_t)(void); +typedef long dispatch_once_t; +void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); + +#ifndef O_CREAT +#define O_CREAT 0x0200 +#define O_RDONLY 0x0000 +#endif +int open(const char *, int, ...); +int close(int fildes); + +void test_open(const char *path) { + int fd; + fd = open(path, O_RDONLY); // no-warning + if (!fd) + close(fd); + + fd = open(path, O_CREAT); // expected-warning{{Call to 'open' requires a third argument when the 'O_CREAT' flag is set}} + if (!fd) + close(fd); +} + +void test_dispatch_once() { + dispatch_once_t pred = 0; + do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // expected-warning{{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}} +} +void test_dispatch_once_neg() { + static dispatch_once_t pred = 0; + do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // no-warning +} + +void test_pthread_once_aux(); + +void test_pthread_once() { + pthread_once_t pred = {0x30B1BCBA, {0}}; + pthread_once(&pred, test_pthread_once_aux); // expected-warning{{Call to 'pthread_once' uses the local variable 'pred' for the "control" value}} +} +void test_pthread_once_neg() { + static pthread_once_t pred = {0x30B1BCBA, {0}}; + pthread_once(&pred, test_pthread_once_aux); // no-warning +} + +// PR 2899 - warn of zero-sized allocations to malloc(). +void pr2899() { + char* foo = malloc(0); // expected-warning{{Call to 'malloc' has an allocation size of 0 bytes}} + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void pr2899_nowarn(size_t size) { + char* foo = malloc(size); // no-warning + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_calloc(void) { + char *foo = calloc(0, 42); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}} + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_calloc2(void) { + char *foo = calloc(42, 0); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}} + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_calloc_nowarn(size_t nmemb, size_t size) { + char *foo = calloc(nmemb, size); // no-warning + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_realloc(char *ptr) { + char *foo = realloc(ptr, 0); // expected-warning{{Call to 'realloc' has an allocation size of 0 bytes}} + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_realloc_nowarn(char *ptr, size_t size) { + char *foo = realloc(ptr, size); // no-warning + for (unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_alloca() { + char *foo = alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}} + for(unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_alloca_nowarn(size_t sz) { + char *foo = alloca(sz); // no-warning + for(unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_builtin_alloca() { + char *foo2 = __builtin_alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}} + for(unsigned i = 0; i < 100; i++) { + foo2[i] = 0; + } +} +void test_builtin_alloca_nowarn(size_t sz) { + char *foo2 = __builtin_alloca(sz); // no-warning + for(unsigned i = 0; i < 100; i++) { + foo2[i] = 0; + } +} +void test_valloc() { + char *foo = valloc(0); // expected-warning{{Call to 'valloc' has an allocation size of 0 bytes}} + for(unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} +void test_valloc_nowarn(size_t sz) { + char *foo = valloc(sz); // no-warning + for(unsigned i = 0; i < 100; i++) { + foo[i] = 0; + } +} diff --git a/clang/test/Analysis/unreachable-code-path.c b/clang/test/Analysis/unreachable-code-path.c new file mode 100644 index 0000000..48a3462 --- /dev/null +++ b/clang/test/Analysis/unreachable-code-path.c @@ -0,0 +1,141 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s + +extern void foo(int a); + +// The first few tests are non-path specific - we should be able to find them + +void test(unsigned a) { + switch (a) { + a += 5; // expected-warning{{never executed}} + case 2: + a *= 10; + case 3: + a %= 2; + } + foo(a); +} + +void test2(unsigned a) { + help: + if (a > 0) + return; + if (a == 0) + return; + foo(a); // expected-warning{{never executed}} + goto help; +} + +void test3(unsigned a) { + while(1); + if (a > 5) { // expected-warning{{never executed}} + return; + } +} + +// These next tests are path-sensitive + +void test4() { + int a = 5; + + while (a > 1) + a -= 2; + + if (a > 1) { + a = a + 56; // expected-warning{{never executed}} + } + + foo(a); +} + +extern void bar(char c); + +void test5(const char *c) { + foo(c[0]); + + if (!c) { + bar(1); // expected-warning{{never executed}} + } +} + +// These next tests are false positives and should not generate warnings + +void test6(const char *c) { + if (c) return; + if (!c) return; + __builtin_unreachable(); // no-warning +} + +// Compile-time constant false positives +#define CONSTANT 0 +enum test_enum { Off, On }; +void test7() { + if (CONSTANT) + return; // no-warning + + if (sizeof(int)) + return; // no-warning + + if (Off) + return; // no-warning +} + +void test8() { + static unsigned a = 0; + + if (a) + a = 123; // no-warning + + a = 5; +} + +// Check for bugs where multiple statements are reported +void test9(unsigned a) { + switch (a) { + if (a) // expected-warning{{never executed}} + foo(a + 5); // no-warning + else // no-warning + foo(a); // no-warning + case 1: + case 2: + break; + default: + break; + } +} + +// Tests from flow-sensitive version +void test10() { + goto c; + d: + goto e; // expected-warning {{never executed}} + c: ; + int i; + return; + goto b; // expected-warning {{never executed}} + goto a; // expected-warning {{never executed}} + b: + i = 1; // no-warning + a: + i = 2; // no-warning + goto f; + e: + goto d; + f: ; +} + +// test11: we can actually end up in the default case, even if it is not +// obvious: there might be something wrong with the given argument. +enum foobar { FOO, BAR }; +extern void error(); +void test11(enum foobar fb) { + switch (fb) { + case FOO: + break; + case BAR: + break; + default: + error(); // no-warning + return; + error(); // expected-warning {{never executed}} + } +} diff --git a/clang/test/Analysis/unused-ivars.m b/clang/test/Analysis/unused-ivars.m new file mode 100644 index 0000000..8941840 --- /dev/null +++ b/clang/test/Analysis/unused-ivars.m @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars -verify -Wno-objc-root-class %s + +//===--- BEGIN: Delta-debugging reduced headers. --------------------------===// + +@protocol NSObject +- (id)retain; +- (oneway void)release; +@end +@interface NSObject <NSObject> {} +- (id)init; ++ (id)alloc; +@end + +//===--- END: Delta-debugging reduced headers. ----------------------------===// + +// This test case tests the basic functionality of the unused ivar test. +@interface TestA { +@private + int x; // expected-warning {{Instance variable 'x' in class 'TestA' is never used}} +} +@end +@implementation TestA @end + +// This test case tests whether the unused ivar check handles blocks that +// reference an instance variable. (<rdar://problem/7075531>) +@interface TestB : NSObject { +@private + id _ivar; // no-warning +} +@property (readwrite,retain) id ivar; +@end + +@implementation TestB +- (id)ivar { + __attribute__((__blocks__(byref))) id value = ((void*)0); + void (^b)() = ^{ value = _ivar; }; + b(); + return value; +} + +- (void)setIvar:(id)newValue { + void (^b)() = ^{ [_ivar release]; _ivar = [newValue retain]; }; + b(); +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/6260004> Detect that ivar is in use, if used in category +// in the same file as the implementation +//===----------------------------------------------------------------------===// + +@protocol Protocol6260004 +- (id) getId; +@end + +@interface RDar6260004 { +@private + id x; // no-warning +} +@end +@implementation RDar6260004 @end +@implementation RDar6260004 (Protocol6260004) +- (id) getId { + return x; +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/7254495> - ivars referenced by lexically nested functions +// should not be flagged as unused +//===----------------------------------------------------------------------===// + +@interface RDar7254495 { +@private + int x; // no-warning +} +@end + +@implementation RDar7254495 +int radar_7254495(RDar7254495 *a) { + return a->x; +} +@end + +//===----------------------------------------------------------------------===// +// <rdar://problem/7353683> - consult attribute((unused)) to silence warnings +// about unused instance variables +//===----------------------------------------------------------------------===// + +@interface RDar7353683 { +@private + id x __attribute__((unused)); +} +@end + +@implementation RDar7353683 +@end +//===----------------------------------------------------------------------===// +// <rdar://problem/8481311> Unused bitfield ivars trigger cause weird +// diagnostic: "Instance variable '' in class..." +//===----------------------------------------------------------------------===// + +@interface RDar8481311 { +@private + unsigned bitfield:1; // expected-warning {{Instance variable 'bitfield' in class 'RDar8481311' is never used}} +} +@end + +@implementation RDar8481311 +@end diff --git a/clang/test/Analysis/variadic-method-types.m b/clang/test/Analysis/variadic-method-types.m new file mode 100644 index 0000000..4d0f6bc --- /dev/null +++ b/clang/test/Analysis/variadic-method-types.m @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=region -fblocks -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. +//===----------------------------------------------------------------------===// + +#define nil (void*)0 +typedef const struct __CFString * CFStringRef; +extern const CFStringRef kCGImageSourceShouldCache __attribute__((visibility("default"))); +typedef signed char BOOL; +typedef struct _NSZone NSZone; +typedef unsigned int NSUInteger; +@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 +@class NSCoder; +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject <NSObject> {} +- (id)init; ++ (id)alloc; +@end +typedef struct {} NSFastEnumerationState; +@protocol NSFastEnumeration +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; +@end +@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +@end +@interface NSArray (NSArrayCreation) ++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +@end +@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +@end +@interface NSDictionary (NSDictionaryCreation) ++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1))); +- (id)initWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1))); +@end +@interface NSSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +@end +@interface NSSet (NSSetCreation) ++ (id)setWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +@end +@interface NSOrderedSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> +@end +@interface NSOrderedSet (NSOrderedSetCreation) ++ (id)orderedSetWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); +@end +@protocol P; +@class C; + +typedef struct FooType * __attribute__ ((NSObject)) FooType; +typedef struct BarType * BarType; + + +void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) { + [NSArray arrayWithObjects:@"Hello", a, b, c, d, nil]; + [NSArray arrayWithObjects:@"Foo", ^{}, nil]; + + [NSArray arrayWithObjects:@"Foo", "Bar", "Baz", nil]; // expected-warning 2 {{Argument to 'NSArray' method 'arrayWithObjects:' should be an Objective-C pointer type, not 'char *'}} + [NSDictionary dictionaryWithObjectsAndKeys:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}} + [NSSet setWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSSet' method 'setWithObjects:' should be an Objective-C pointer type, not 'char *'}} + [NSOrderedSet orderedSetWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSOrderedSet' method 'orderedSetWithObjects:' should be an Objective-C pointer type, not 'char *'}} + + [[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSArray' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}} + [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}} + [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", (void*) 0, nil] autorelease]; // no-warning + [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", kCGImageSourceShouldCache, nil] autorelease]; // no-warning + [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", fooType, nil] autorelease]; // no-warning + [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", barType, nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}} + [[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSSet' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}} + [[[NSOrderedSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSOrderedSet' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}} +} + +// This previously crashed the variadic argument checker. +@protocol RDar9273215 +- (void)rdar9273215:(id)x, ...; +@end + +void test_rdar9273215(id<RDar9273215> y) { + return [y rdar9273215:y, y]; +} + diff --git a/clang/test/Analysis/virtualcall.cpp b/clang/test/Analysis/virtualcall.cpp new file mode 100644 index 0000000..127d04f --- /dev/null +++ b/clang/test/Analysis/virtualcall.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.cplusplus.VirtualCall -analyzer-store region -verify %s + +class A { +public: + A(); + ~A() {}; + + virtual int foo() = 0; + virtual void bar() = 0; + void f() { + foo(); // expected-warning{{Call pure virtual functions during construction or destruction may leads undefined behaviour}} + } +}; + +class B : public A { +public: + B() { + foo(); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}} + } + ~B(); + + virtual int foo(); + virtual void bar() { foo(); } // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}} +}; + +A::A() { + f(); +} + +B::~B() { + this->B::foo(); // no-warning + this->B::bar(); + this->foo(); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}} +} + +class C : public B { +public: + C(); + ~C(); + + virtual int foo(); + void f(int i); +}; + +C::C() { + f(foo()); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}} +} + +int main() { + A *a; + B *b; + C *c; +} |