| // RUN: %clang_analyze_cc1 -fblocks \ |
| // RUN: -analyzer-checker=core \ |
| // RUN: -analyzer-checker=osx.cocoa.MissingSuperCall \ |
| // RUN: -analyzer-checker=osx.cocoa.NSError \ |
| // RUN: -analyzer-checker=osx.ObjCProperty \ |
| // RUN: -analyzer-checker=osx.cocoa.RetainCount \ |
| // RUN: -analyzer-checker=unix.Malloc \ |
| // RUN: -analyzer-checker=alpha.core.CastToStruct \ |
| // RUN: -Wno-unused-value -Wno-objc-root-class -verify %s |
| |
| #define SUPPRESS __attribute__((suppress)) |
| #define SUPPRESS_SPECIFIC(...) __attribute__((suppress(__VA_ARGS__))) |
| |
| @protocol NSObject |
| - (id)retain; |
| - (oneway void)release; |
| @end |
| @interface NSObject <NSObject> { |
| } |
| - (id)init; |
| + (id)alloc; |
| @end |
| typedef int NSInteger; |
| typedef char BOOL; |
| typedef struct _NSZone NSZone; |
| @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; |
| @protocol NSCopying |
| - (id)copyWithZone:(NSZone *)zone; |
| @end |
| @protocol NSCoding |
| - (void)encodeWithCoder:(NSCoder *)aCoder; |
| @end |
| @class NSDictionary; |
| @interface NSError : NSObject <NSCopying, NSCoding> { |
| } |
| + (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict; |
| @end |
| |
| @interface NSMutableString : NSObject |
| @end |
| |
| typedef __typeof__(sizeof(int)) size_t; |
| void *malloc(size_t); |
| void free(void *); |
| |
| void dereference_1() { |
| int *x = 0; |
| *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| |
| void dereference_suppression_1() { |
| int *x = 0; |
| SUPPRESS { *x; } // no-warning |
| } |
| |
| void dereference_2() { |
| int *x = 0; |
| if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| } |
| |
| void dereference_suppression_2() { |
| int *x = 0; |
| SUPPRESS if (*x) { // no-warning |
| } |
| } |
| |
| void dereference_suppression_2a() { |
| int *x = 0; |
| // FIXME: Implement suppressing individual checkers. |
| SUPPRESS_SPECIFIC("core.NullDereference") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| } |
| |
| void dereference_suppression_2b() { |
| int *x = 0; |
| // This is not a MallocChecker issue so it shouldn't be suppressed. (Though the attribute |
| // doesn't really understand any of those arguments yet.) |
| SUPPRESS_SPECIFIC("unix.Malloc") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| } |
| |
| void dereference_3(int cond) { |
| int *x = 0; |
| if (cond) { |
| (*x)++; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| } |
| |
| void dereference_suppression_3(int cond) { |
| int *x = 0; |
| SUPPRESS if (cond) { |
| (*x)++; // no-warning |
| } |
| } |
| |
| void dereference_4() { |
| int *x = 0; |
| int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| |
| void dereference_suppression_4() { |
| int *x = 0; |
| SUPPRESS int y = *x; // no-warning |
| } |
| |
| void dereference_5() { |
| int *x = 0; |
| int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| int z = *x; // no-warning (duplicate) |
| } |
| |
| void dereference_suppression_5_1() { |
| int *x = 0; |
| SUPPRESS int y = *x; // no-warning |
| int z = *x; // no-warning (duplicate) |
| } |
| |
| void dereference_suppression_5_2() { |
| int *x = 0; |
| int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| SUPPRESS int z = *x; // no-warning |
| } |
| |
| void do_deref(int *y) { |
| *y = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'y')}} |
| } |
| |
| void dereference_interprocedural() { |
| int *x = 0; |
| do_deref(x); |
| } |
| |
| void do_deref_suppressed(int *y) { |
| SUPPRESS *y = 1; // no-warning |
| } |
| |
| void dereference_interprocedural_suppressed() { |
| int *x = 0; |
| do_deref_suppressed(x); |
| } |
| |
| int malloc_leak_1() { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| return *x; // expected-warning{{Potential leak of memory pointed to by 'x'}} |
| } |
| |
| int malloc_leak_suppression_1_1() { |
| SUPPRESS int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| return *x; |
| } |
| |
| int malloc_leak_suppression_1_2() { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| SUPPRESS return *x; |
| } |
| |
| void malloc_leak_2() { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| } // expected-warning{{Potential leak of memory pointed to by 'x'}} |
| |
| void malloc_leak_suppression_2_1() { |
| SUPPRESS int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| } |
| |
| void malloc_leak_suppression_2_2() SUPPRESS { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| } // no-warning |
| |
| SUPPRESS void malloc_leak_suppression_2_3() { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| } // no-warning |
| |
| void malloc_leak_suppression_2_4(int cond) { |
| int *x = (int *)malloc(sizeof(int)); |
| *x = 42; |
| SUPPRESS; |
| // FIXME: The warning should be suppressed but dead symbol elimination |
| // happens too late. |
| } // expected-warning{{Potential leak of memory pointed to by 'x'}} |
| |
| void retain_release_leak_1() { |
| [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object of type 'NSMutableString *'}} |
| } |
| |
| void retain_release_leak_suppression_1() { |
| SUPPRESS { [[NSMutableString alloc] init]; } |
| } |
| |
| void retain_release_leak_2(int cond) { |
| id obj = [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object stored into 'obj'}} |
| if (cond) { |
| [obj release]; |
| } |
| } |
| |
| void retain_release_leak__suppression_2(int cond) { |
| SUPPRESS id obj = [[NSMutableString alloc] init]; |
| if (cond) { |
| [obj release]; |
| } |
| } |
| |
| @interface UIResponder : NSObject { |
| } |
| - (char)resignFirstResponder; |
| @end |
| |
| @interface Test : UIResponder { |
| } |
| @property(copy) NSMutableString *mutableStr; |
| // expected-warning@-1 {{Property of mutable type 'NSMutableString' has 'copy' attribute; an immutable object will be stored instead}} |
| @end |
| @implementation Test |
| |
| - (BOOL)resignFirstResponder { |
| return 0; |
| } // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'Test' is missing a [super resignFirstResponder] call}} |
| |
| - (void)methodWhichMayFail:(NSError **)error { |
| // expected-warning@-1 {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}} |
| } |
| @end |
| |
| @interface TestSuppress : UIResponder { |
| } |
| @property(copy) SUPPRESS NSMutableString *mutableStr; // no-warning |
| @end |
| @implementation TestSuppress |
| |
| - (BOOL)resignFirstResponder SUPPRESS { // no-warning |
| return 0; |
| } |
| |
| - (void)methodWhichMayFail:(NSError **)error SUPPRESS { // no-warning |
| } |
| @end |
| |
| struct AB { |
| int A, B; |
| }; |
| |
| struct ABC { |
| int A, B, C; |
| }; |
| |
| void ast_checker_1() { |
| struct AB Ab; |
| struct ABC *Abc; |
| Abc = (struct ABC *)&Ab; // expected-warning {{Casting data to a larger structure type and accessing a field can lead to memory access errors or data corruption}} |
| } |
| |
| void ast_checker_suppress_1() { |
| struct AB Ab; |
| struct ABC *Abc; |
| SUPPRESS { Abc = (struct ABC *)&Ab; } |
| } |
| |
| SUPPRESS int suppressed_function() { |
| int *x = 0; |
| return *x; // no-warning |
| } |
| |
| SUPPRESS int suppressed_function_forward(); |
| int suppressed_function_forward() { |
| int *x = 0; |
| return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| |
| int suppressed_function_backward(); |
| SUPPRESS int suppressed_function_backward() { |
| int *x = 0; |
| return *x; // no-warning |
| } |
| |
| SUPPRESS |
| @interface SuppressedInterface |
| -(int)suppressedMethod; |
| -(int)regularMethod SUPPRESS; |
| @end |
| |
| @implementation SuppressedInterface |
| -(int)suppressedMethod SUPPRESS { |
| int *x = 0; |
| return *x; // no-warning |
| } |
| |
| // This one is NOT suppressed by the attribute on the forward declaration, |
| // and it's also NOT suppressed by the attribute on the entire interface. |
| -(int)regularMethod { |
| int *x = 0; |
| return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| } |
| @end |