blob: 6bddbef58f1db3e1610aef56c22e657ebd631358 [file] [log] [blame]
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,deadcode.DeadStores,osx.cocoa.RetainCount,unix.Malloc,unix.MismatchedDeallocator -analyzer-output=plist -analyzer-config deadcode.DeadStores:ShowFixIts=true -o %t -w %s
// RUN: %normalize_plist <%t | diff -ub %S/Inputs/expected-plists/edges-new.mm.plist -
//===----------------------------------------------------------------------===//
// Forward declarations (from headers).
//===----------------------------------------------------------------------===//
typedef const struct __CFNumber * CFNumberRef;
typedef const struct __CFAllocator * CFAllocatorRef;
extern const CFAllocatorRef kCFAllocatorDefault;
typedef signed long CFIndex;
enum {
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
typedef CFIndex CFNumberType;
CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
#define nil ((id)0)
__attribute__((objc_root_class))
@interface NSObject
+ (instancetype) alloc;
- (instancetype) init;
- (instancetype)retain;
- (void)release;
@end
@interface NSArray : NSObject
@end
//===----------------------------------------------------------------------===//
// Basic tracking of null and tests for null.
//===----------------------------------------------------------------------===//
void test_null_init(void) {
int *p = 0;
*p = 0xDEADBEEF;
}
void test_null_assign(void) {
int *p;
p = 0;
*p = 0xDEADBEEF;
}
void test_null_assign_transitive(void) {
int *p;
p = 0;
int *q = p;
*q = 0xDEADBEEF;
}
void test_null_cond(int *p) {
if (!p) {
*p = 0xDEADBEEF;
}
}
void test_null_cond_transitive(int *q) {
if (!q) {
int *p = q;
*p = 0xDEADBEEF;
}
}
void test_null_field(void) {
struct s { int *p; } x;
x.p = 0;
*(x.p) = 0xDEADBEEF;
}
void test_assumptions(int a, int b)
{
if (a == 0) {
return;
}
if (b != 0) {
return;
}
int *p = 0;
*p = 0xDEADBEEF;
}
int *bar_cond_assign();
int test_cond_assign() {
int *p;
if ((p = bar_cond_assign()))
return 1;
return *p;
}
//===----------------------------------------------------------------------===//
// Diagnostics for leaks and "noreturn" paths.
//===----------------------------------------------------------------------===//
// <rdar://problem/8331641> leak reports should not show paths that end with exit() (but ones that don't end with exit())
void stop() __attribute__((noreturn));
void rdar8331641(int x) {
signed z = 1;
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
if (x)
stop();
(void) value;
}
//===----------------------------------------------------------------------===//
// Test loops and control-flow.
//===----------------------------------------------------------------------===//
void test_objc_fast_enumeration(NSArray *x) {
id obj;
for (obj in x)
*(volatile int *)0 = 0;
}
void test_objc_fast_enumeration_2(id arr) {
int x;
for (id obj in arr) {
x = 1;
}
x += 1;
}
// Test that loops are documented in the path.
void rdar12280665() {
for (unsigned i = 0; i < 2; ++i) {
if (i == 1) {
int *p = 0;
*p = 0xDEADBEEF; // expected-warning {{dereference}}
}
}
}
// Test for a "loop executed 0 times" diagnostic.
int *radar12322528_bar();
void radar12322528_for(int x) {
int z;
int *p = 0;
for (unsigned i = 0; i < x; ++i) {
p = radar12322528_bar();
}
*p = 0xDEADBEEF;
}
void radar12322528_while(int x) {
int *p = 0;
unsigned i = 0;
for ( ; i < x ; ) {
++i;
p = radar12322528_bar();
}
*p = 0xDEADBEEF;
}
void radar12322528_foo_2() {
int *p = 0;
for (unsigned i = 0; i < 2; ++i) {
if (i == 0)
continue;
if (i == 1) {
break;
}
}
*p = 0xDEADBEEF;
}
void test_loop_diagnostics() {
int *p = 0;
for (int i = 0; i < 2; ++i) { p = 0; }
*p = 1;
}
void test_loop_diagnostics_2() {
int *p = 0;
for (int i = 0; i < 2; ) {
++i;
p = 0;
}
*p = 1;
}
void test_loop_diagnostics_3() {
int z;
int y;
int k;
int *p = 0;
int i = 0;
while (i < 2) {
++i;
p = 0;
}
* p = 1;
}
void test_do_while() {
unsigned i = 0;
int *p;
do {
++i;
p = 0;
} while (i< 2);
*p = 0xDEADBEEF;
}
void test_logical_and() {
int *p = 0;
if (1 && 2) {
*p = 0xDEADBEEF;
}
}
void test_logical_or() {
int *p = 0;
if (0 || 2) {
*p = 0xDEADBEEF;
}
}
void test_logical_or_call() {
extern int call(int);
int *p = 0;
if (call(0 || 2)) {
*p = 0xDEADBEEF;
}
}
void test_nested_logicals(int coin) {
int *p = 0;
if ((0 || 0) || coin) {
*p = 0xDEADBEEF;
}
if (0 || (0 || !coin)) {
*p = 0xDEADBEEF;
}
}
void test_deeply_nested_logicals() {
extern int call(int);
int *p = 0;
if ((0 || (5 && 0)) ? 0 : ((0 || 4) ? call(1 && 5) : 0)) {
*p = 0xDEADBEEF;
}
}
void test_ternary(int x, int *y) {
int z = x ? 0 : 1;
int *p = z ? y : 0;
*p = 0xDEADBEEF;
}
void testUseless(int *y) {
if (y) {
}
if (y) {
}
int *p = 0;
*p = 0xDEADBEEF;
}
//===----------------------------------------------------------------------===//
// Interprocedural tests.
//===----------------------------------------------------------------------===//
@interface IPA_Foo
- (int *) returnsPointer;
@end
int testFoo(IPA_Foo *x) {
if (x)
return 1;
return *[x returnsPointer];
}
@interface IPA_X : NSObject
- (int *)getPointer;
@end
void test1_IPA_X() {
IPA_X *x = nil;
*[x getPointer] = 1; // here
}
@interface IPA_Y : NSObject
- (IPA_Y *)opaque;
- (IPA_X *)getX;
@end
@implementation IPA_Y
- (IPA_X *)getX {
return nil;
}
@end
void test_IPA_Y(IPA_Y *y) {
if (y)
return;
IPA_X *x = [[y opaque] getX]; // here
*[x getPointer] = 1;
}
// From diagnostics/report-issues-within-main-file.cpp:
void causeDivByZeroInMain(int in) {
int m = 0;
m = in/m;
m++;
}
void mainPlusMain() {
int i = 0;
i++;
causeDivByZeroInMain(i);
i++;
}
// From inlining/path-notes.c:
int *getZero() {
int *p = 0;
return p;
}
void usePointer(int *p) {
*p = 1;
}
void testUseOfNullPointer() {
// Test the case where an argument expression is itself a call.
usePointer(getZero());
}
//===----------------------------------------------------------------------===//
// Misc. tests.
//===----------------------------------------------------------------------===//
// Test for tracking null state of ivars.
@interface RDar12114812 : NSObject { char *p; }
@end
@implementation RDar12114812
- (void)test {
p = 0;
*p = 1;
}
@end
// Test diagnostics for initialization of structs.
void RDar13295437_f(void *i) __attribute__((__nonnull__));
struct RDar13295437_S { int *i; };
int RDar13295437() {
struct RDar13295437_S s = {0};
struct RDar13295437_S *sp = &s;
RDar13295437_f(sp->i);
return 0;
}
void testCast(int coin) {
if (coin) {
(void)(1+2);
(void)(2+3);
(void)(3+4);
*(volatile int *)0 = 1;
}
}
// The following previously crashed when generating extensive diagnostics.
// <rdar://problem/10797980>
@interface RDar10797980_help
@property (readonly) int x;
@end
@interface RDar10797980 : NSObject {
RDar10797980_help *y;
}
- (void) test;
@end
@implementation RDar10797980
- (void) test {
if (y.x == 1) {
int *p = 0;
*p = 0xDEADBEEF; // expected-warning {{deference}}
}
}
// The original source for the above Radar contains another problem:
// if the end-of-path node is an implicit statement, it may not have a valid
// source location. <rdar://problem/12446776>
- (void)test2 {
if (bar_cond_assign()) {
id foo = [[RDar10797980 alloc] init]; // leak
}
(void)y; // first statement after the 'if' is an implicit 'self' DeclRefExpr
}
@end
void variousLoops(id input) {
extern int a();
extern int b();
extern int c();
extern int work();
while (a()) {
work();
work();
work();
*(volatile int *)0 = 1;
}
int first = 1;
do {
work();
work();
work();
if (!first)
*(volatile int *)0 = 1;
first = 0;
} while (a());
for (int i = 0; i != b(); ++i) {
work();
*(volatile int *)0 = 1;
}
for (id x in input) {
work();
work();
work();
(void)x;
*(volatile int *)0 = 1;
}
int z[] = {1,2};
for (int y : z) {
work();
work();
work();
(void)y;
}
int empty[] = {};
for (int y : empty) {
work();
work();
work();
(void)y;
}
for (int i = 0; ; ++i) {
work();
if (i == b())
break;
}
int i;
for (i = 0; i != b(); ++i) {
work();
*(volatile int *)0 = 1;
}
for (; i != b(); ++i) {
work();
*(volatile int *)0 = 1;
}
for (; i != b(); ) {
work();
if (i == b())
break;
*(volatile int *)0 = 1;
}
for (;;) {
work();
if (i == b())
break;
}
*(volatile int *)0 = 1;
}
void *malloc(unsigned long);
void *realloc(void *, unsigned long);
void free(void *);
void reallocDiagnostics() {
char * buf = (char*)malloc(100);
char * tmp;
tmp = (char*)realloc(buf, 0x1000000);
if (!tmp) {
return;// expected-warning {{leak}}
}
buf = tmp;
free(buf);
}
template <typename T>
class unique_ptr {
T *ptr;
public:
explicit unique_ptr(T *p) : ptr(p) {}
~unique_ptr() { delete ptr; }
};
void test() {
int i = 0;
++i;
unique_ptr<int> p(new int[4]);
{
++i;
}
}
void longLines() {
id foo = [[NSObject alloc] init]; // leak
id bar =
[foo retain];
[bar release];
id baz = [foo
retain];
[baz release];
// This next line is intentionally longer than 80 characters.
id garply = [foo retain];
[garply release];
}
#define POINTER(T) T*
POINTER(void) testMacroInFunctionDecl(void *q) {
int *p = 0;
*p = 1;
return q;
}
namespace rdar14960554 {
class Foo {
int a = 1;
int b = 2;
int c = 3;
Foo() :
a(0),
c(3) {
// Check that we don't have an edge to the in-class initializer for 'b'.
if (b == 2)
*(volatile int *)0 = 1;
}
};
}