summaryrefslogtreecommitdiff
path: root/test/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis')
-rw-r--r--test/Analysis/bstring.c36
-rw-r--r--test/Analysis/misc-ps-eager-assume.m1
-rw-r--r--test/Analysis/nullptr.cpp8
-rw-r--r--test/Analysis/objc-arc.m149
-rw-r--r--test/Analysis/pr4209.m6
-rw-r--r--test/Analysis/retain-release-gc-only.m1
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m74
-rw-r--r--test/Analysis/retain-release-path-notes.m123
-rw-r--r--test/Analysis/retain-release.m87
-rw-r--r--test/Analysis/retain-release.mm1
-rw-r--r--test/Analysis/string-fail.c113
-rw-r--r--test/Analysis/string.c402
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m5
-rw-r--r--test/Analysis/uninit-vals-ps-region.m9
-rw-r--r--test/Analysis/uninit-vals.m9
-rw-r--r--test/Analysis/variadic-method-types.m8
16 files changed, 895 insertions, 137 deletions
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index 68bbb1a5b2f5a..cd43e36d03510 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -64,14 +64,14 @@ void memcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ 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{{Byte string function overflows destination buffer}}
+ memcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
void memcpy3 () {
@@ -85,14 +85,14 @@ void memcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ 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{{Byte string function overflows destination buffer}}
+ memcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
}
void memcpy6() {
@@ -118,12 +118,12 @@ void memcpy9() {
void memcpy10() {
char a[4] = {0};
- memcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void memcpy12() {
@@ -144,7 +144,7 @@ void memcpy_unknown_size (size_t n) {
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 byte string function}}
+ if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
@@ -186,14 +186,14 @@ void mempcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- mempcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ 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{{Byte string function overflows destination buffer}}
+ mempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy3 () {
@@ -207,14 +207,14 @@ void mempcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- mempcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+ 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{{Byte string function overflows destination buffer}}
+ mempcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy6() {
@@ -240,12 +240,12 @@ void mempcpy9() {
void mempcpy10() {
char a[4] = {0};
- mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void mempcpy12() {
@@ -260,7 +260,7 @@ void mempcpy13() {
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 byte string function}}
+ if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index 649c4b07f5439..4380a187b8002 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -12,6 +12,7 @@ typedef struct _NSZone NSZone;
@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;
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index b74a5abcdfa4b..6f78baebfe22a 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -39,3 +39,11 @@ void foo4(void) {
*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;
+}
+
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
new file mode 100644
index 0000000000000..6b22fd099b06e
--- /dev/null
+++ b/test/Analysis/objc-arc.m
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-checker=deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
+
+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 NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)alloc;
+@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;
+}
+
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index 1e0fd32fcd03b..e3bc5cc143331 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -49,17 +49,17 @@ CMProfileLocation;
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}}
+-(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}} expected-note {{using}}
@end @interface GSEbayCategory : NSObject <NSCoding> {
}
-- (int) categoryID;
+- (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]];
+ GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; // expected-warning {{multiple methods named 'categoryID' found}}
if (rootCategory != category) {
GSEbayCategory *parent = category;
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index cbf00a27721d8..ee1a6b4b782e0 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -113,6 +113,7 @@ NSFastEnumerationState;
@end @interface NSAutoreleasePool : NSObject {
}
- (void)drain;
+- (id)init;
@end extern NSString * const NSBundleDidLoadNotification;
typedef double NSTimeInterval;
@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
new file mode 100644
index 0000000000000..21d314fa15418
--- /dev/null
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -fobjc-gc-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -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/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
new file mode 100644
index 0000000000000..bac0afb3f7abc
--- /dev/null
+++ b/test/Analysis/retain-release-path-notes.m
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -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 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 counte}}
+ 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 counte}}
+ 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 return from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given 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}}
+}
+@end
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 7af14f129c3f6..71ae756cf0454 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -116,6 +116,7 @@ typedef struct _NSZone NSZone;
- (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;
@@ -517,7 +518,7 @@ void f17(int x, CFTypeRef p) {
@implementation TestReturnNotOwnedWhenExpectedOwned
- (NSString*)newString {
NSString *s = [NSString stringWithUTF8String:"hello"];
- return s; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ return s; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
@@ -735,7 +736,7 @@ typedef CFTypeRef OtherRef;
- (id)initReturningNewClassBad2 {
[self release];
self = [[RDar6320065Subclass alloc] init];
- return [self autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ return [self autorelease]; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
@@ -1302,7 +1303,7 @@ CFDateRef returnsRetainedCFDate() {
}
- (CFDateRef) newCFRetainedAsCFNoAttr {
- return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+ 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 {
@@ -1445,7 +1446,7 @@ static void rdar_8724287(CFErrorRef error)
while (error_to_dump != ((void*)0)) {
CFDictionaryRef info;
- info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1448 and stored into 'info'}}
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1449 and stored into 'info'}}
if (info != ((void*)0)) {
}
@@ -1461,3 +1462,81 @@ 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}}
+}
+
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index 0faeb1a2a3005..bdc3dc03964a4 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -121,6 +121,7 @@ typedef struct _NSZone NSZone;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
+- (id)init;
@end
@interface NSObject (NSCoderMethods)
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
diff --git a/test/Analysis/string-fail.c b/test/Analysis/string-fail.c
new file mode 100644
index 0000000000000..64ac504d6d805
--- /dev/null
+++ b/test/Analysis/string-fail.c
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.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/test/Analysis/string.c b/test/Analysis/string.c
index e6baf51c474cf..dc97e1a119e01 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -55,16 +55,16 @@ void strlen_constant2(char x) {
}
size_t strlen_null() {
- return strlen(0); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+ 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 byte string function is the address of the label 'label', which is not a null-terminated string}}
+ 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() {
@@ -143,24 +143,23 @@ void strlen_liveness(const char *x) {
// strnlen()
//===----------------------------------------------------------------------===
-#define strnlen BUILTIN(strnlen)
size_t strnlen(const char *s, size_t maxlen);
void strnlen_constant0() {
if (strnlen("123", 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant1() {
const char *a = "123";
if (strnlen(a, 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant2(char x) {
char a[] = "123";
if (strnlen(a, 10) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
a[0] = x;
if (strnlen(a, 10) != 3)
(void)*(char*)0; // expected-warning{{null}}
@@ -168,107 +167,90 @@ void strnlen_constant2(char x) {
void strnlen_constant4() {
if (strnlen("123456", 3) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant5() {
const char *a = "123456";
if (strnlen(a, 3) != 3)
- (void)*(char*)0; // no-warning
+ (void)*(char*)0; // expected-warning{{never executed}}
}
void strnlen_constant6(char x) {
char a[] = "123456";
if (strnlen(a, 3) != 3)
- (void)*(char*)0; // no-warning
+ (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 byte string function}}
+ 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 byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+ 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 byte string function is the address of the label 'label', which is not a null-terminated string}}
+ 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_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 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);
+}
- use_two_stringsn(&z);
+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);
+}
- size_t c = strnlen(z.a, 10);
- if (a == 0 && c != 0)
+void strnlen_is_not_strlen(char *x) {
+ if (strnlen(x, 10) != strlen(x))
(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 strnlen_at_limit(char *x) {
+ size_t len = strnlen(x, 10);
+ if (len > 10)
(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}}
+ if (len == 10)
+ (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 strnlen_less_than_limit(char *x) {
+ size_t len = strnlen(x, 10);
+ if (len > 10)
(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_str, 10);
- if (a == 0 && c != 0)
- (void)*(char*)0; // expected-warning{{null}}
+ if (len < 10)
+ (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 strnlen_at_actual(size_t limit) {
+ size_t len = strnlen("abc", limit);
+ if (len > 3)
(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)
+ if (len == 3)
(void)*(char*)0; // expected-warning{{null}}
}
-void strnlen_liveness(const char *x) {
- if (strnlen(x, 10) < 5)
- return;
- if (strnlen(x, 10) < 5)
- (void)*(char*)0; // no-warning
+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}}
}
//===----------------------------------------------------------------------===
@@ -291,15 +273,15 @@ char *strcpy(char *restrict s1, const char *restrict s2);
void strcpy_null_dst(char *x) {
- strcpy(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ 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 byte string function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
+ 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_effects(char *x, char *y) {
@@ -318,7 +300,7 @@ void strcpy_effects(char *x, char *y) {
void strcpy_overflow(char *y) {
char x[4];
if (strlen(y) == 4)
- strcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ strcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcpy_no_overflow(char *y) {
@@ -362,7 +344,7 @@ void stpcpy_effect(char *x, char *y) {
void stpcpy_overflow(char *y) {
char x[4];
if (strlen(y) == 4)
- stpcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ stpcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void stpcpy_no_overflow(char *y) {
@@ -391,15 +373,15 @@ char *strcat(char *restrict s1, const char *restrict s2);
void strcat_null_dst(char *x) {
- strcat(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ 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 byte string function is the address of the function 'strcat_fn', which is not a null-terminated string}}
+ 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) {
@@ -415,27 +397,24 @@ void strcat_effects(char *y) {
if ((int)strlen(x) != (orig_len + strlen(y)))
(void)*(char*)0; // no-warning
-
- if (a != x[0])
- (void)*(char*)0; // expected-warning{{null}}
}
void strcat_overflow_0(char *y) {
char x[4] = "12";
if (strlen(y) == 4)
- strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+ 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{{Byte string function overflows destination buffer}}
+ 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{{Byte string function overflows destination buffer}}
+ strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
void strcat_no_overflow(char *y) {
@@ -444,6 +423,136 @@ void strcat_no_overflow(char *y) {
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_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()
@@ -465,15 +574,15 @@ char *strncat(char *restrict s1, const char *restrict s2, size_t n);
void strncat_null_dst(char *x) {
- strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ 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 byte string function is the address of the function 'strncat_fn', which is not a null-terminated string}}
+ 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) {
@@ -489,33 +598,30 @@ void strncat_effects(char *y) {
if (strlen(x) != orig_len + strlen(y))
(void)*(char*)0; // no-warning
-
- if (a != x[0])
- (void)*(char*)0; // expected-warning{{null}}
}
void strncat_overflow_0(char *y) {
char x[4] = "12";
if (strlen(y) == 4)
- strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+ 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{{Byte string function overflows destination buffer}}
+ 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{{Byte string function overflows destination buffer}}
+ 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{{Byte string function overflows destination buffer}}
+ 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";
@@ -529,12 +635,69 @@ void strncat_no_overflow_2(char *y) {
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 *restrict s1, const char *restrict s2);
+int strcmp(const char * s1, const char * s2);
void strcmp_constant0() {
if (strcmp("123", "123") != 0)
@@ -577,13 +740,13 @@ void strcmp_2() {
void strcmp_null_0() {
char *x = NULL;
char *y = "123";
- strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ strcmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcmp_diff_length_0() {
@@ -614,12 +777,22 @@ void strcmp_diff_length_3() {
(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 *restrict s1, const char *restrict s2, size_t n);
+int strncmp(const char *s1, const char *s2, size_t n);
void strncmp_constant0() {
if (strncmp("123", "123", 3) != 0)
@@ -662,13 +835,13 @@ void strncmp_2() {
void strncmp_null_0() {
char *x = NULL;
char *y = "123";
- strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncmp_diff_length_0() {
@@ -720,12 +893,17 @@ void strncmp_diff_length_6() {
(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 *restrict s1, const char *restrict s2);
+int strcasecmp(const char *s1, const char *s2);
void strcasecmp_constant0() {
if (strcasecmp("abc", "Abc") != 0)
@@ -768,13 +946,13 @@ void strcasecmp_2() {
void strcasecmp_null_0() {
char *x = NULL;
char *y = "123";
- strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ strcasecmp(x, y); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strcasecmp_diff_length_0() {
@@ -805,12 +983,17 @@ void strcasecmp_diff_length_3() {
(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 *restrict s1, const char *restrict s2, size_t n);
+int strncasecmp(const char *s1, const char *s2, size_t n);
void strncasecmp_constant0() {
if (strncasecmp("abc", "Abc", 3) != 0)
@@ -853,13 +1036,13 @@ void strncasecmp_2() {
void strncasecmp_null_0() {
char *x = NULL;
char *y = "123";
- strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+ 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 byte string function}}
+ strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to string comparison function}}
}
void strncasecmp_diff_length_0() {
@@ -910,3 +1093,8 @@ void strncasecmp_diff_length_6() {
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/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
index f1794068d5e16..f4df91396a844 100644
--- a/test/Analysis/uninit-ps-rdar6145427.m
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -11,7 +11,10 @@ typedef struct _NSZone NSZone;
@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; @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;
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 1700f54dbfb08..c62818a12e0d7 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -67,3 +67,12 @@ void rdar_7780304() {
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/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 2cd5e0c118487..4b7e6f42cf8f4 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -23,3 +23,12 @@ NSUInteger f8(A* x){
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/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
index 018956ab1b2d7..03c309a5004aa 100644
--- a/test/Analysis/variadic-method-types.m
+++ b/test/Analysis/variadic-method-types.m
@@ -73,13 +73,13 @@ void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) {
[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 *'}}
- [[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
- [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjectsAndKeys:' 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 method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}}
- [[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [[[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 *'}}
}
// This previously crashed the variadic argument checker.