271 lines
7.4 KiB
Objective-C
271 lines
7.4 KiB
Objective-C
// 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;
|
|
}
|
|
|
|
// TODO: reassess when we decide what to do with declaration annotations
|
|
void malloc_leak_suppression_2_2() /* SUPPRESS */ {
|
|
int *x = (int *)malloc(sizeof(int));
|
|
*x = 42;
|
|
} // expected-warning{{Potential leak of memory pointed to by 'x'}}
|
|
|
|
// TODO: reassess when we decide what to do with declaration annotations
|
|
/* SUPPRESS */ void malloc_leak_suppression_2_3() {
|
|
int *x = (int *)malloc(sizeof(int));
|
|
*x = 42;
|
|
} // expected-warning{{Potential leak of memory pointed to by 'x'}}
|
|
|
|
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 {
|
|
}
|
|
// TODO: reassess when we decide what to do with declaration annotations
|
|
@property(copy) /* SUPPRESS */ NSMutableString *mutableStr;
|
|
// expected-warning@-1 {{Property of mutable type 'NSMutableString' has 'copy' attribute; an immutable object will be stored instead}}
|
|
@end
|
|
@implementation TestSuppress
|
|
|
|
// TODO: reassess when we decide what to do with declaration annotations
|
|
- (BOOL)resignFirstResponder /* SUPPRESS */ {
|
|
return 0;
|
|
} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'TestSuppress' is missing a [super resignFirstResponder] call}}
|
|
|
|
// TODO: reassess when we decide what to do with declaration annotations
|
|
- (void)methodWhichMayFail:(NSError **)error /* SUPPRESS */ {
|
|
// expected-warning@-1 {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}}
|
|
}
|
|
@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; }
|
|
}
|