// 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