302 lines · plain
1// RUN: %clang_analyze_cc1 -fblocks \2// RUN: -analyzer-checker=core \3// RUN: -analyzer-checker=osx.cocoa.MissingSuperCall \4// RUN: -analyzer-checker=osx.cocoa.NSError \5// RUN: -analyzer-checker=osx.ObjCProperty \6// RUN: -analyzer-checker=osx.cocoa.RetainCount \7// RUN: -analyzer-checker=unix.Malloc \8// RUN: -analyzer-checker=alpha.core.CastToStruct \9// RUN: -Wno-unused-value -Wno-objc-root-class -verify %s10 11#define SUPPRESS __attribute__((suppress))12#define SUPPRESS_SPECIFIC(...) __attribute__((suppress(__VA_ARGS__)))13 14@protocol NSObject15- (id)retain;16- (oneway void)release;17@end18@interface NSObject <NSObject> {19}20- (id)init;21+ (id)alloc;22@end23typedef int NSInteger;24typedef char BOOL;25typedef struct _NSZone NSZone;26@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;27@protocol NSCopying28- (id)copyWithZone:(NSZone *)zone;29@end30@protocol NSCoding31- (void)encodeWithCoder:(NSCoder *)aCoder;32@end33@class NSDictionary;34@interface NSError : NSObject <NSCopying, NSCoding> {35}36+ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;37@end38 39@interface NSMutableString : NSObject40@end41 42typedef __typeof__(sizeof(int)) size_t;43void *malloc(size_t);44void free(void *);45 46void dereference_1() {47 int *x = 0;48 *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}49}50 51void dereference_suppression_1() {52 int *x = 0;53 SUPPRESS { *x; } // no-warning54}55 56void dereference_2() {57 int *x = 0;58 if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}59 }60}61 62void dereference_suppression_2() {63 int *x = 0;64 SUPPRESS if (*x) { // no-warning65 }66}67 68void dereference_suppression_2a() {69 int *x = 0;70 // FIXME: Implement suppressing individual checkers.71 SUPPRESS_SPECIFIC("core.NullDereference") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}72 }73}74 75void dereference_suppression_2b() {76 int *x = 0;77 // This is not a MallocChecker issue so it shouldn't be suppressed. (Though the attribute78 // doesn't really understand any of those arguments yet.)79 SUPPRESS_SPECIFIC("unix.Malloc") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}80 }81}82 83void dereference_3(int cond) {84 int *x = 0;85 if (cond) {86 (*x)++; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}87 }88}89 90void dereference_suppression_3(int cond) {91 int *x = 0;92 SUPPRESS if (cond) {93 (*x)++; // no-warning94 }95}96 97void dereference_4() {98 int *x = 0;99 int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}100}101 102void dereference_suppression_4() {103 int *x = 0;104 SUPPRESS int y = *x; // no-warning105}106 107void dereference_5() {108 int *x = 0;109 int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}110 int z = *x; // no-warning (duplicate)111}112 113void dereference_suppression_5_1() {114 int *x = 0;115 SUPPRESS int y = *x; // no-warning116 int z = *x; // no-warning (duplicate)117}118 119void dereference_suppression_5_2() {120 int *x = 0;121 int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}122 SUPPRESS int z = *x; // no-warning123}124 125void do_deref(int *y) {126 *y = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'y')}}127}128 129void dereference_interprocedural() {130 int *x = 0;131 do_deref(x);132}133 134void do_deref_suppressed(int *y) {135 SUPPRESS *y = 1; // no-warning136}137 138void dereference_interprocedural_suppressed() {139 int *x = 0;140 do_deref_suppressed(x);141}142 143int malloc_leak_1() {144 int *x = (int *)malloc(sizeof(int));145 *x = 42;146 return *x; // expected-warning{{Potential leak of memory pointed to by 'x'}}147}148 149int malloc_leak_suppression_1_1() {150 SUPPRESS int *x = (int *)malloc(sizeof(int));151 *x = 42;152 return *x;153}154 155int malloc_leak_suppression_1_2() {156 int *x = (int *)malloc(sizeof(int));157 *x = 42;158 SUPPRESS return *x;159}160 161void malloc_leak_2() {162 int *x = (int *)malloc(sizeof(int));163 *x = 42;164} // expected-warning{{Potential leak of memory pointed to by 'x'}}165 166void malloc_leak_suppression_2_1() {167 SUPPRESS int *x = (int *)malloc(sizeof(int));168 *x = 42;169}170 171void malloc_leak_suppression_2_2() SUPPRESS {172 int *x = (int *)malloc(sizeof(int));173 *x = 42;174} // no-warning175 176SUPPRESS void malloc_leak_suppression_2_3() {177 int *x = (int *)malloc(sizeof(int));178 *x = 42;179} // no-warning180 181void malloc_leak_suppression_2_4(int cond) {182 int *x = (int *)malloc(sizeof(int));183 *x = 42;184 SUPPRESS;185 // FIXME: The warning should be suppressed but dead symbol elimination186 // happens too late.187} // expected-warning{{Potential leak of memory pointed to by 'x'}}188 189void retain_release_leak_1() {190 [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object of type 'NSMutableString *'}}191}192 193void retain_release_leak_suppression_1() {194 SUPPRESS { [[NSMutableString alloc] init]; }195}196 197void retain_release_leak_2(int cond) {198 id obj = [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object stored into 'obj'}}199 if (cond) {200 [obj release];201 }202}203 204void retain_release_leak__suppression_2(int cond) {205 SUPPRESS id obj = [[NSMutableString alloc] init];206 if (cond) {207 [obj release];208 }209}210 211@interface UIResponder : NSObject {212}213- (char)resignFirstResponder;214@end215 216@interface Test : UIResponder {217}218@property(copy) NSMutableString *mutableStr;219// expected-warning@-1 {{Property of mutable type 'NSMutableString' has 'copy' attribute; an immutable object will be stored instead}}220@end221@implementation Test222 223- (BOOL)resignFirstResponder {224 return 0;225} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'Test' is missing a [super resignFirstResponder] call}}226 227- (void)methodWhichMayFail:(NSError **)error {228 // expected-warning@-1 {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}}229}230@end231 232@interface TestSuppress : UIResponder {233}234@property(copy) SUPPRESS NSMutableString *mutableStr; // no-warning235@end236@implementation TestSuppress237 238- (BOOL)resignFirstResponder SUPPRESS { // no-warning239 return 0;240}241 242- (void)methodWhichMayFail:(NSError **)error SUPPRESS { // no-warning243}244@end245 246struct AB {247 int A, B;248};249 250struct ABC {251 int A, B, C;252};253 254void ast_checker_1() {255 struct AB Ab;256 struct ABC *Abc;257 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}}258}259 260void ast_checker_suppress_1() {261 struct AB Ab;262 struct ABC *Abc;263 SUPPRESS { Abc = (struct ABC *)&Ab; }264}265 266SUPPRESS int suppressed_function() {267 int *x = 0;268 return *x; // no-warning269}270 271SUPPRESS int suppressed_function_forward();272int suppressed_function_forward() {273 int *x = 0;274 return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}275}276 277int suppressed_function_backward();278SUPPRESS int suppressed_function_backward() {279 int *x = 0;280 return *x; // no-warning281}282 283SUPPRESS284@interface SuppressedInterface285-(int)suppressedMethod;286-(int)regularMethod SUPPRESS;287@end288 289@implementation SuppressedInterface290-(int)suppressedMethod SUPPRESS {291 int *x = 0;292 return *x; // no-warning293}294 295// This one is NOT suppressed by the attribute on the forward declaration,296// and it's also NOT suppressed by the attribute on the entire interface.297-(int)regularMethod {298 int *x = 0;299 return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}300}301@end302