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 -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;
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
|