forked from OSchip/llvm-project
593 lines
10 KiB
Plaintext
593 lines
10 KiB
Plaintext
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,deadcode.DeadStores,osx.cocoa.RetainCount,unix.Malloc,unix.MismatchedDeallocator -analyzer-output=plist -o %t -w %s
|
||
// RUN: cat %t | %diff_plist %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;
|
||
}
|
||
};
|
||
}
|
||
|