summaryrefslogtreecommitdiffstats
path: root/test/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis')
-rw-r--r--test/Analysis/additive-folding.c14
-rw-r--r--test/Analysis/array-struct-region.c47
-rw-r--r--test/Analysis/bstring.c37
-rw-r--r--test/Analysis/constant-folding.c74
-rw-r--r--test/Analysis/dead-stores.c32
-rw-r--r--test/Analysis/flat-store.c11
-rw-r--r--test/Analysis/idempotent-operations.c203
-rw-r--r--test/Analysis/idempotent-operations.cpp15
-rw-r--r--test/Analysis/malloc.c124
-rw-r--r--test/Analysis/misc-ps-region-store.cpp27
-rw-r--r--test/Analysis/misc-ps-region-store.m101
-rw-r--r--test/Analysis/misc-ps.m58
-rw-r--r--test/Analysis/null-deref-ps.c9
-rw-r--r--test/Analysis/outofbound.c24
-rw-r--r--test/Analysis/plist-output.m2
-rw-r--r--test/Analysis/retain-release-region-store.m27
-rw-r--r--test/Analysis/retain-release.m9
-rw-r--r--test/Analysis/stack-addr-ps.cpp8
-rw-r--r--test/Analysis/stream.c38
-rw-r--r--test/Analysis/string.c240
-rw-r--r--test/Analysis/uninit-vals-ps-region.m4
-rw-r--r--test/Analysis/unreachable-code-path.c104
22 files changed, 1097 insertions, 111 deletions
diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c
index 15d7588..e4a5651 100644
--- a/test/Analysis/additive-folding.c
+++ b/test/Analysis/additive-folding.c
@@ -18,7 +18,7 @@ void separateExpressions (int a) {
char* buf = malloc(1);
if (a != 0 && b == 0)
- return; // no-warning
+ return; // expected-warning{{never executed}}
free(buf);
}
@@ -29,7 +29,7 @@ void oneLongExpression (int a) {
char* buf = malloc(1);
if (a != 0 && b == 0)
- return; // no-warning
+ return; // expected-warning{{never executed}}
free(buf);
}
@@ -40,11 +40,11 @@ void mixedTypes (int a) {
// This is part of PR7406.
int b = a + 1LL;
if (a != 0 && (b-1) == 0) // not crash
- return; // no warning
+ return; // expected-warning{{never executed}}
int c = a + 1U;
if (a != 0 && (c-1) == 0) // not crash
- return; // no warning
+ return; // expected-warning{{never executed}}
free(buf);
}
@@ -85,7 +85,7 @@ void mixed_eq_ne (int a) {
if (a+1U != 2)
return; // no-warning
if (a-1U != 0)
- return; // no-warning
+ return; // expected-warning{{never executed}}
free(b);
}
@@ -96,7 +96,7 @@ void mixed_ne_eq (int a) {
if (a+1U == 2)
return; // no-warning
if (a-1U == 0)
- return; // no-warning
+ return; // expected-warning{{never executed}}
free(b);
}
@@ -191,7 +191,7 @@ void tautologyGE (unsigned a) {
void tautologyLT (unsigned a) {
char* b = malloc(1);
if (a < 0)
- return; // no-warning
+ return; // expected-warning{{never executed}}
free(b);
}
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
new file mode 100644
index 0000000..dabd25b
--- /dev/null
+++ b/test/Analysis/array-struct-region.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -analyze -analyzer-experimental-checks -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-checks -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+
+int string_literal_init() {
+ char a[] = "abc";
+ char b[2] = "abc"; // expected-warning{{too long}}
+ char c[5] = "abc";
+
+ if (a[1] != 'b')
+ return 0; // expected-warning{{never executed}}
+ if (b[1] != 'b')
+ return 0; // expected-warning{{never executed}}
+ if (c[1] != 'b')
+ return 0; // expected-warning{{never executed}}
+
+ if (a[3] != 0)
+ return 0; // expected-warning{{never executed}}
+ if (c[3] != 0)
+ return 0; // expected-warning{{never executed}}
+
+ if (c[4] != 0)
+ return 0; // expected-warning{{never executed}}
+
+ return 42;
+}
+
+void nested_compound_literals(int rad) {
+ int vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169},
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ int a;
+
+ for (a = 0; a < 6; ++a) {
+ vec[a][0] *= rad; // no-warning
+ vec[a][1] *= rad; // no-warning
+ }
+}
+
+void nested_compound_literals_float(float rad) {
+ float vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169},
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ int a;
+
+ for (a = 0; a < 6; ++a) {
+ vec[a][0] *= rad; // no-warning
+ vec[a][1] *= rad; // no-warning
+ }
+}
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index f4ddb0a..ffe420f 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -48,27 +48,30 @@ void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void memcpy0 () {
char src[] = {1, 2, 3, 4};
- char dst[4];
+ char dst[4] = {0};
memcpy(dst, src, 4); // no-warning
if (memcpy(dst, src, 4) != dst) {
- (void)*(char*)0; // no-warning -- should be unreachable
+ (void)*(char*)0; // no-warning
}
+
+ if (dst[0] != 0)
+ (void)*(char*)0; // expected-warning{{null}}
}
void memcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst, src, 5); // expected-warning{{out-of-bound}}
+ memcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
}
void memcpy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
- memcpy(dst, src, 4); // expected-warning{{out-of-bound}}
+ memcpy(dst, src, 4); // expected-warning{{Byte string function overflows destination buffer}}
}
void memcpy3 () {
@@ -82,14 +85,14 @@ void memcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
- memcpy(dst+2, src+2, 3); // expected-warning{{out-of-bound}}
+ memcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
}
void memcpy5() {
char src[] = {1, 2, 3, 4};
char dst[3];
- memcpy(dst+2, src+2, 2); // expected-warning{{out-of-bound}}
+ memcpy(dst+2, src+2, 2); // expected-warning{{Byte string function overflows destination buffer}}
}
void memcpy6() {
@@ -150,13 +153,16 @@ void *memmove(void *s1, const void *s2, size_t n);
void memmove0 () {
char src[] = {1, 2, 3, 4};
- char dst[4];
+ char dst[4] = {0};
memmove(dst, src, 4); // no-warning
if (memmove(dst, src, 4) != dst) {
- (void)*(char*)0; // no-warning -- should be unreachable
+ (void)*(char*)0; // no-warning
}
+
+ if (dst[0] != 0)
+ (void)*(char*)0; // expected-warning{{null}}
}
void memmove1 () {
@@ -170,7 +176,7 @@ void memmove2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
- memmove(dst, src, 4); // expected-warning{{out-of-bound}}
+ memmove(dst, src, 4); // expected-warning{{overflow}}
}
//===----------------------------------------------------------------------===
@@ -246,6 +252,12 @@ void memcmp6 (char *a, char *b, size_t n) {
(void)*(char*)0; // expected-warning{{null}}
}
+int memcmp7 (char *a, size_t x, size_t y, size_t n) {
+ // We used to crash when either of the arguments was unknown.
+ return memcmp(a, &a[x*y], n) +
+ memcmp(&a[x*y], a, n);
+}
+
//===----------------------------------------------------------------------===
// bcopy()
//===----------------------------------------------------------------------===
@@ -257,9 +269,12 @@ void bcopy(/*const*/ void *s1, void *s2, size_t n);
void bcopy0 () {
char src[] = {1, 2, 3, 4};
- char dst[4];
+ char dst[4] = {0};
bcopy(src, dst, 4); // no-warning
+
+ if (dst[0] != 0)
+ (void)*(char*)0; // expected-warning{{null}}
}
void bcopy1 () {
@@ -273,5 +288,5 @@ void bcopy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
- bcopy(src, dst, 4); // expected-warning{{out-of-bound}}
+ bcopy(src, dst, 4); // expected-warning{{overflow}}
}
diff --git a/test/Analysis/constant-folding.c b/test/Analysis/constant-folding.c
index 6ed2b39..9191a9e 100644
--- a/test/Analysis/constant-folding.c
+++ b/test/Analysis/constant-folding.c
@@ -9,51 +9,51 @@ void testComparisons (int a) {
// Sema can already catch the simple comparison a==a,
// since that's usually a logic error (and not path-dependent).
int b = a;
- if (!(b==a)) WARN;
- if (!(b>=a)) WARN;
- if (!(b<=a)) WARN;
- if (b!=a) WARN;
- if (b>a) WARN;
- if (b<a) WARN;
+ if (!(b==a)) WARN; // expected-warning{{never executed}}
+ if (!(b>=a)) WARN; // expected-warning{{never executed}}
+ if (!(b<=a)) WARN; // expected-warning{{never executed}}
+ if (b!=a) WARN; // expected-warning{{never executed}}
+ if (b>a) WARN; // expected-warning{{never executed}}
+ if (b<a) WARN; // expected-warning{{never executed}}
}
void testSelfOperations (int a) {
- if ((a|a) != a) WARN;
- if ((a&a) != a) WARN;
- if ((a^a) != 0) WARN;
- if ((a-a) != 0) WARN;
+ if ((a|a) != a) WARN; // expected-warning{{never executed}}
+ if ((a&a) != a) WARN; // expected-warning{{never executed}}
+ if ((a^a) != 0) WARN; // expected-warning{{never executed}}
+ if ((a-a) != 0) WARN; // expected-warning{{never executed}}
}
void testIdempotent (int a) {
- if ((a*1) != a) WARN;
- if ((a/1) != a) WARN;
- if ((a+0) != a) WARN;
- if ((a-0) != a) WARN;
- if ((a<<0) != a) WARN;
- if ((a>>0) != a) WARN;
- if ((a^0) != a) WARN;
- if ((a&(~0)) != a) WARN;
- if ((a|0) != a) WARN;
+ if ((a*1) != a) WARN; // expected-warning{{never executed}}
+ if ((a/1) != a) WARN; // expected-warning{{never executed}}
+ if ((a+0) != a) WARN; // expected-warning{{never executed}}
+ if ((a-0) != a) WARN; // expected-warning{{never executed}}
+ if ((a<<0) != a) WARN; // expected-warning{{never executed}}
+ if ((a>>0) != a) WARN; // expected-warning{{never executed}}
+ if ((a^0) != a) WARN; // expected-warning{{never executed}}
+ if ((a&(~0)) != a) WARN; // expected-warning{{never executed}}
+ if ((a|0) != a) WARN; // expected-warning{{never executed}}
}
void testReductionToConstant (int a) {
- if ((a*0) != 0) WARN;
- if ((a&0) != 0) WARN;
- if ((a|(~0)) != (~0)) WARN;
+ if ((a*0) != 0) WARN; // expected-warning{{never executed}}
+ if ((a&0) != 0) WARN; // expected-warning{{never executed}}
+ if ((a|(~0)) != (~0)) WARN; // expected-warning{{never executed}}
}
void testSymmetricIntSymOperations (int a) {
- if ((2+a) != (a+2)) WARN;
- if ((2*a) != (a*2)) WARN;
- if ((2&a) != (a&2)) WARN;
- if ((2^a) != (a^2)) WARN;
- if ((2|a) != (a|2)) WARN;
+ if ((2+a) != (a+2)) WARN; // expected-warning{{never executed}}
+ if ((2*a) != (a*2)) WARN; // expected-warning{{never executed}}
+ if ((2&a) != (a&2)) WARN; // expected-warning{{never executed}}
+ if ((2^a) != (a^2)) WARN; // expected-warning{{never executed}}
+ if ((2|a) != (a|2)) WARN; // expected-warning{{never executed}}
}
void testAsymmetricIntSymOperations (int a) {
- if (((~0) >> a) != (~0)) WARN;
- if ((0 >> a) != 0) WARN;
- if ((0 << a) != 0) WARN;
+ if (((~0) >> a) != (~0)) WARN; // expected-warning{{never executed}}
+ if ((0 >> a) != 0) WARN; // expected-warning{{never executed}}
+ if ((0 << a) != 0) WARN; // expected-warning{{never executed}}
// Unsigned right shift shifts in zeroes.
if ((((unsigned)(~0)) >> ((unsigned) a)) != ((unsigned)(~0)))
@@ -62,11 +62,11 @@ void testAsymmetricIntSymOperations (int a) {
void testLocations (char *a) {
char *b = a;
- if (!(b==a)) WARN;
- if (!(b>=a)) WARN;
- if (!(b<=a)) WARN;
- if (b!=a) WARN;
- if (b>a) WARN;
- if (b<a) WARN;
- if (b-a) WARN;
+ if (!(b==a)) WARN; // expected-warning{{never executed}}
+ if (!(b>=a)) WARN; // expected-warning{{never executed}}
+ if (!(b<=a)) WARN; // expected-warning{{never executed}}
+ if (b!=a) WARN; // expected-warning{{never executed}}
+ if (b>a) WARN; // expected-warning{{never executed}}
+ if (b<a) WARN; // expected-warning{{never executed}}
+ if (b-a) WARN; // expected-warning{{never executed}}
}
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index defd7e0..57d5d11 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
@@ -150,7 +150,7 @@ void f15(unsigned x, unsigned y) {
int f16(int x) {
x = x * 2;
- x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{Although the value stored to 'x' is used}}
+ x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{Although the value stored to 'x' is used}} expected-warning{{The left operand to '*' is always 1}}
? 5 : 8;
return x;
}
@@ -158,7 +158,7 @@ int f16(int x) {
// Self-assignments should not be flagged as dead stores.
void f17() {
int x = 1;
- x = x; // no-warning
+ x = x;
}
// <rdar://problem/6506065>
@@ -458,7 +458,31 @@ void rdar8014335() {
// Note that the next value stored to 'i' is never executed
// because the next statement to be executed is the 'break'
// in the increment code of the first loop.
- i = i * 3; // expected-warning{{Value stored to 'i' is never read}}
+ i = i * 3; // expected-warning{{Value stored to 'i' is never read}} expected-warning{{The left operand to '*' is always 1}}
}
}
+// <rdar://problem/8320674> NullStmts followed by do...while() can lead to disconnected CFG
+//
+// This previously caused bogus dead-stores warnings because the body of the first do...while was
+// disconnected from the entry of the function.
+typedef struct { float r; float i; } s_rdar8320674;
+typedef struct { s_rdar8320674 x[1]; } s2_rdar8320674;
+
+void rdar8320674(s_rdar8320674 *z, unsigned y, s2_rdar8320674 *st, int m)
+{
+ s_rdar8320674 * z2;
+ s_rdar8320674 * tw1 = st->x;
+ s_rdar8320674 t;
+ z2 = z + m;
+ do{
+ ; ;
+ do{ (t).r = (*z2).r*(*tw1).r - (*z2).i*(*tw1).i; (t).i = (*z2).r*(*tw1).i + (*z2).i*(*tw1).r; }while(0);
+ tw1 += y;
+ do { (*z2).r=(*z).r-(t).r; (*z2).i=(*z).i-(t).i; }while(0);
+ do { (*z).r += (t).r; (*z).i += (t).i; }while(0);
+ ++z2;
+ ++z;
+ }while (--m);
+}
+
diff --git a/test/Analysis/flat-store.c b/test/Analysis/flat-store.c
new file mode 100644
index 0000000..bb274b0
--- /dev/null
+++ b/test/Analysis/flat-store.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s
+#define FAIL ((void)*(char*)0)
+struct simple { int x; };
+
+void PR7297 () {
+ struct simple a;
+ struct simple *p = &a;
+ p->x = 5;
+ if (!p[0].x) FAIL; // no-warning
+ if (p[0].x) FAIL; // expected-warning {{null}}
+}
diff --git a/test/Analysis/idempotent-operations.c b/test/Analysis/idempotent-operations.c
index 9cef08e..5c9a59d 100644
--- a/test/Analysis/idempotent-operations.c
+++ b/test/Analysis/idempotent-operations.c
@@ -1,52 +1,189 @@
-// RUN: %clang_cc1 -analyze -analyzer-idempotent-operation -analyzer-store=region -analyzer-constraints=range -fblocks -verify -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-check-idempotent-operations -verify %s
// Basic tests
extern void test(int i);
+extern void test_f(float f);
-void basic() {
+unsigned basic() {
int x = 10, zero = 0, one = 1;
// x op x
- x = x; // expected-warning {{idempotent operation; both operands are always equal in value}}
- test(x - x); // expected-warning {{idempotent operation; both operands are always equal in value}}
- x -= x; // expected-warning {{idempotent operation; both operands are always equal in value}}
+ x = x; // expected-warning {{Assigned value is always the same as the existing value}}
+ test(x - x); // expected-warning {{Both operands to '-' always have the same value}}
+ x -= x; // expected-warning {{Both operands to '-=' always have the same value}}
x = 10; // no-warning
- test(x / x); // expected-warning {{idempotent operation; both operands are always equal in value}}
- x /= x; // expected-warning {{idempotent operation; both operands are always equal in value}}
+ test(x / x); // expected-warning {{Both operands to '/' always have the same value}}
+ x /= x; // expected-warning {{Both operands to '/=' always have the same value}}
x = 10; // no-warning
- test(x & x); // expected-warning {{idempotent operation; both operands are always equal in value}}
- x &= x; // expected-warning {{idempotent operation; both operands are always equal in value}}
- test(x | x); // expected-warning {{idempotent operation; both operands are always equal in value}}
- x |= x; // expected-warning {{idempotent operation; both operands are always equal in value}}
+ test(x & x); // expected-warning {{Both operands to '&' always have the same value}}
+ x &= x; // expected-warning {{Both operands to '&=' always have the same value}}
+ test(x | x); // expected-warning {{Both operands to '|' always have the same value}}
+ x |= x; // expected-warning {{Both operands to '|=' always have the same value}}
// x op 1
- test(x * one); // expected-warning {{idempotent operation; the right operand is always 1}}
- x *= one; // expected-warning {{idempotent operation; the right operand is always 1}}
- test(x / one); // expected-warning {{idempotent operation; the right operand is always 1}}
- x /= one; // expected-warning {{idempotent operation; the right operand is always 1}}
+ test(x * one); // expected-warning {{The right operand to '*' is always 1}}
+ x *= one; // expected-warning {{The right operand to '*=' is always 1}}
+ test(x / one); // expected-warning {{The right operand to '/' is always 1}}
+ x /= one; // expected-warning {{The right operand to '/=' is always 1}}
// 1 op x
- test(one * x); // expected-warning {{idempotent operation; the left operand is always 1}}
+ test(one * x); // expected-warning {{The left operand to '*' is always 1}}
// x op 0
- test(x + zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x - zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x * zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x & zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x | zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x ^ zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x << zero); // expected-warning {{idempotent operation; the right operand is always 0}}
- test(x >> zero); // expected-warning {{idempotent operation; the right operand is always 0}}
+ test(x + zero); // expected-warning {{The right operand to '+' is always 0}}
+ test(x - zero); // expected-warning {{The right operand to '-' is always 0}}
+ test(x * zero); // expected-warning {{The right operand to '*' is always 0}}
+ test(x & zero); // expected-warning {{The right operand to '&' is always 0}}
+ test(x | zero); // expected-warning {{The right operand to '|' is always 0}}
+ test(x ^ zero); // expected-warning {{The right operand to '^' is always 0}}
+ test(x << zero); // expected-warning {{The right operand to '<<' is always 0}}
+ test(x >> zero); // expected-warning {{The right operand to '>>' is always 0}}
// 0 op x
- test(zero + x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero - x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero / x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero * x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero & x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero | x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero ^ x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero << x); // expected-warning {{idempotent operation; the left operand is always 0}}
- test(zero >> x); // expected-warning {{idempotent operation; the left operand is always 0}}
+ test(zero + x); // expected-warning {{The left operand to '+' is always 0}}
+ test(zero - x); // expected-warning {{The left operand to '-' is always 0}}
+ test(zero / x); // expected-warning {{The left operand to '/' is always 0}}
+ test(zero * x); // expected-warning {{The left operand to '*' is always 0}}
+ test(zero & x); // expected-warning {{The left operand to '&' is always 0}}
+ test(zero | x); // expected-warning {{The left operand to '|' is always 0}}
+ test(zero ^ x); // expected-warning {{The left operand to '^' is always 0}}
+ test(zero << x); // expected-warning {{The left operand to '<<' is always 0}}
+ test(zero >> x); // expected-warning {{The left operand to '>>' is always 0}}
+
+ // Overwrite the values so these aren't marked as Pseudoconstants
+ x = 1;
+ zero = 2;
+ one = 3;
+
+ return x + zero + one;
+}
+
+void floats(float x) {
+ test_f(x * 1.0); // no-warning
+ test_f(x * 1.0F); // no-warning
+}
+
+// Ensure that we don't report false poitives in complex loops
+void bailout() {
+ int unused = 0, result = 4;
+ result = result; // expected-warning {{Assigned value is always the same as the existing value}}
+
+ for (unsigned bg = 0; bg < 1024; bg ++) {
+ result = bg * result; // no-warning
+
+ for (int i = 0; i < 256; i++) {
+ unused *= i; // no-warning
+ }
+ }
+}
+
+// Relaxed liveness - check that we don't kill liveness at assignments
+typedef unsigned uintptr_t;
+void kill_at_assign() {
+ short array[2];
+ uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}}
+ short *p = x; // expected-warning{{incompatible integer to pointer conversion}}
+
+ // The following branch should be infeasible.
+ if (!(p = &array[0])) { // expected-warning{{Assigned value is always the same as the existing value}}
+ p = 0;
+ *p = 1; // no-warning
+ }
+}
+
+// False positive tests
+
+unsigned false1() {
+ int a = 10;
+ return a * (5 - 2 - 3); // no-warning
+}
+
+enum testenum { enum1 = 0, enum2 };
+unsigned false2() {
+ int a = 1234;
+ return enum1 + a; // no-warning
+}
+
+// Self assignments of unused variables are common false positives
+unsigned false3(int param, int param2) {
+ param = param; // no-warning
+
+ // if a self assigned variable is used later, then it should be reported still
+ param2 = param2; // expected-warning{{Assigned value is always the same as the existing value}}
+
+ unsigned nonparam = 5;
+
+ nonparam = nonparam; // expected-warning{{Assigned value is always the same as the existing value}}
+
+ return param2 + nonparam;
+}
+
+// Pseudo-constants (vars only read) and constants should not be reported
+unsigned false4() {
+ // Trivial constant
+ const int height = 1;
+ int c = 42;
+ test(height * c); // no-warning
+
+ // Pseudo-constant (never changes after decl)
+ int width = height;
+
+ return width * 10; // no-warning
+}
+
+// Block pseudoconstants
+void false4a() {
+ // Pseudo-constant
+ __block int a = 1;
+ int b = 10;
+ __block int c = 0;
+ b *= a; // no-warning
+
+ ^{
+ // Psuedoconstant block var
+ test(b * c); // no-warning
+
+ // Non-pseudoconstant block var
+ int d = 0;
+ test(b * d); // expected-warning{{The right operand to '*' is always 0}}
+ d = 5;
+ test(d);
+ }();
+
+ test(a + b);
+}
+
+// Static vars are common false positives
+int false5() {
+ static int test = 0;
+ int a = 56;
+ a *= test; // no-warning
+ test++;
+ return a;
+}
+
+// Non-local storage vars are considered false positives
+int globalInt = 1;
+int false6() {
+ int localInt = 23;
+
+ localInt /= globalInt;
+
+ return localInt;
+}
+
+// Check that assignments filter out false positives correctly
+int false7() {
+ int zero = 0; // psuedo-constant
+ int one = 1;
+
+ int a = 55;
+ a = a; // expected-warning{{Assigned value is always the same as the existing value}}
+ a = enum1 * a; // no-warning
+
+ int b = 123;
+ b = b; // no-warning
+
+ return a;
}
diff --git a/test/Analysis/idempotent-operations.cpp b/test/Analysis/idempotent-operations.cpp
new file mode 100644
index 0000000..c5d1ceb
--- /dev/null
+++ b/test/Analysis/idempotent-operations.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-check-idempotent-operations -verify %s
+
+// C++ specific false positives
+
+extern void test(int i);
+extern void test_ref(int &i);
+
+// Test references affecting pseudoconstants
+void false1() {
+ int a = 0;
+ int five = 5;
+ int &b = a;
+ test(five * a); // expected-warning {{The right operand to '*' is always 0}}
+ b = 4;
+}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index b4c1314..e443150 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -4,22 +4,136 @@ void *malloc(size_t);
void free(void *);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+void __attribute((ownership_returns(malloc, 1))) *my_malloc2(size_t);
+void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
+
+// Duplicate attributes are silly, but not an error.
+// Duplicate attribute has no extra effect.
+// If two are of different kinds, that is an error and reported as such.
+void __attribute((ownership_holds(malloc, 1)))
+__attribute((ownership_holds(malloc, 1)))
+__attribute((ownership_holds(malloc, 3))) my_hold2(void *, void *, void *);
+void *my_malloc3(size_t);
+void *myglobalpointer;
+struct stuff {
+ void *somefield;
+};
+struct stuff myglobalstuff;
void f1() {
int *p = malloc(12);
return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
}
-void f1_b() {
- int *p = malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
-}
-
void f2() {
int *p = malloc(12);
free(p);
free(p); // expected-warning{{Try to free a memory block that has been released}}
}
+// ownership attributes tests
+void naf1() {
+ int *p = my_malloc3(12);
+ return; // no-warning
+}
+
+void n2af1() {
+ int *p = my_malloc2(12);
+ return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+}
+
+void af1() {
+ int *p = my_malloc(12);
+ return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+}
+
+void af1_b() {
+ int *p = my_malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
+}
+
+void af1_c() {
+ myglobalpointer = my_malloc(12); // no-warning
+}
+
+void af1_d() {
+ struct stuff mystuff;
+ mystuff.somefield = my_malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
+}
+
+// Test that we can pass out allocated memory via pointer-to-pointer.
+void af1_e(void **pp) {
+ *pp = my_malloc(42); // no-warning
+}
+
+void af1_f(struct stuff *somestuff) {
+ somestuff->somefield = my_malloc(12); // no-warning
+}
+
+// Allocating memory for a field via multiple indirections to our arguments is OK.
+void af1_g(struct stuff **pps) {
+ *pps = my_malloc(sizeof(struct stuff)); // no-warning
+ (*pps)->somefield = my_malloc(42); // no-warning
+}
+
+void af2() {
+ int *p = my_malloc(12);
+ my_free(p);
+ free(p); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+void af2b() {
+ int *p = my_malloc(12);
+ free(p);
+ my_free(p); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+void af2c() {
+ int *p = my_malloc(12);
+ free(p);
+ my_hold(p); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+void af2d() {
+ int *p = my_malloc(12);
+ free(p);
+ my_hold2(0, 0, p); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+// No leak if malloc returns null.
+void af2e() {
+ int *p = my_malloc(12);
+ if (!p)
+ return; // no-warning
+ free(p); // no-warning
+}
+
+// This case would inflict a double-free elsewhere.
+// However, this case is considered an analyzer bug since it causes false-positives.
+void af3() {
+ int *p = my_malloc(12);
+ my_hold(p);
+ free(p); // no-warning
+}
+
+// This case would inflict a double-free elsewhere.
+// However, this case is considered an analyzer bug since it causes false-positives.
+int * af4() {
+ int *p = my_malloc(12);
+ my_free(p);
+ return p; // no-warning
+}
+
+// This case is (possibly) ok, be conservative
+int * af5() {
+ int *p = my_malloc(12);
+ my_hold(p);
+ return p; // no-warning
+}
+
+
+
// This case tests that storing malloc'ed memory to a static variable which is
// then returned is not leaked. In the absence of known contracts for functions
// or inter-procedural analysis, this is a conservative answer.
@@ -117,7 +231,7 @@ char callocZeroesBad () {
char *buf = calloc(2,2);
char result = buf[3]; // no-warning
if (buf[1] != 0) {
- free(buf);
+ free(buf); // expected-warning{{never executed}}
}
return result; // expected-warning{{never released}}
}
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 6794d48..bfa5e5c 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -132,3 +132,30 @@ int TestHandleThis::null_deref_positive() {
return 0;
}
+// PR 7675 - passing literals by-reference
+void pr7675(const double &a);
+void pr7675(const int &a);
+void pr7675(const char &a);
+void pr7675_i(const _Complex double &a);
+
+void pr7675_test() {
+ pr7675(10.0);
+ pr7675(10);
+ pr7675('c');
+ pr7675_i(4.0i);
+ // Add null deref to ensure we are analyzing the code up to this point.
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{null pointer}}
+}
+
+// <rdar://problem/8375510> - CFGBuilder should handle temporaries.
+struct R8375510 {
+ R8375510();
+ ~R8375510();
+ R8375510 operator++(int);
+};
+
+int r8375510(R8375510 x, R8375510 y) {
+ for (; ; x++) { }
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 6b4f658..a4e0d0b 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -253,7 +253,7 @@ void rdar_7249327(unsigned int A[2*32]) {
a = A;
b = B;
- n = *a++;
+ n = *a++; // expected-warning{{Assigned value is always the same as the existing value}}
if (n)
x += *b++; // no-warning
}
@@ -1041,3 +1041,102 @@ void pr_7450() {
pr_7450_aux(p + 8);
}
+// <rdar://problem/8243408> - Symbolicate struct values returned by value.
+struct s_rdar_8243408 { int x; };
+extern struct s_rdar_8243408 rdar_8243408_aux(void);
+void rdar_8243408(void) {
+ struct s_rdar_8243408 a = { 1 }, *b = 0;
+ while (a.x && !b)
+ a = rdar_8243408_aux();
+
+ // Previously there was a false error here with 'b' being null.
+ (void) (a.x && b->x); // no-warning
+
+ // Introduce a null deref to ensure we are checking this path.
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+}
+
+// <rdar://problem/8258814>
+int r8258814()
+{
+ int foo;
+ int * a = &foo;
+ a[0] = 10;
+ // Do not warn that the value of 'foo' is uninitialized.
+ return foo; // no-warning
+}
+
+// PR 8052 - Don't crash when reasoning about loads from a function address.\n
+typedef unsigned int __uint32_t;
+typedef unsigned long vm_offset_t;
+typedef __uint32_t pd_entry_t;
+typedef unsigned char u_char;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+extern int bootMP_size;
+void bootMP(void);
+static void
+pr8052(u_int boot_addr)
+{
+ int x;
+ int size = *(int *) ((u_long) & bootMP_size);
+ u_char *src = (u_char *) ((u_long) bootMP);
+ u_char *dst = (u_char *) boot_addr + ((vm_offset_t) ((((((((1 <<
+12) / (sizeof(pd_entry_t))) - 1) - 1) - (260 - 2))) << 22) | ((0) << 12)));
+ for (x = 0;
+ x < size;
+ ++x)
+ *dst++ = *src++;
+}
+
+// PR 8015 - don't return undefined values for arrays when using a valid
+// symbolic index
+int pr8015_A();
+void pr8015_B(const char *);
+
+void pr8015_C() {
+ int number = pr8015_A();
+ const char *numbers[] = { "zero" };
+ if (number == 0) {
+ pr8015_B(numbers[number]); // no-warning
+ }
+}
+
+// FIXME: This is a false positive due to not reasoning about symbolic
+// array indices correctly. Discussion in PR 8015.
+void pr8015_D_FIXME() {
+ int number = pr8015_A();
+ const char *numbers[] = { "zero" };
+ if (number == 0) {
+ if (numbers[number] == numbers[0])
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+ }
+}
+
+void pr8015_E() {
+ // Similar to pr8015_C, but number is allowed to be a valid range.
+ unsigned number = pr8015_A();
+ const char *numbers[] = { "zero", "one", "two" };
+ if (number < 3) {
+ pr8015_B(numbers[number]); // no-warning
+ }
+}
+
+void pr8015_F_FIXME() {
+ // Similar to pr8015_E, but like pr8015_D we check if the pointer
+ // is the same as one of the string literals. The null dereference
+ // here is not feasible in practice, so this is a false positive.
+ int number = pr8015_A();
+ const char *numbers[] = { "zero", "one", "two" };
+ if (number < 3) {
+ const char *p = numbers[number];
+ if (p == numbers[0] || p == numbers[1] || p == numbers[2])
+ return;
+ int *q = 0;
+ *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+ }
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index b1d47e2..4fbaa49 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -86,11 +86,11 @@ unsigned r6268365Aux();
void r6268365() {
unsigned x = 0;
- x &= r6268365Aux();
+ x &= r6268365Aux(); // expected-warning{{The left operand to '&=' is always 0}}
unsigned j = 0;
if (x == 0) ++j;
- if (x == 0) x = x / j; // no-warning
+ if (x == 0) x = x / j; // expected-warning{{Assigned value is always the same as the existing value}} expected-warning{{The right operand to '/' is always 1}}
}
void divzeroassume(unsigned x, unsigned j) {
@@ -298,6 +298,7 @@ void rdar_6777209(char *p) {
typedef void *Opcode;
Opcode pr_4033_getOpcode();
void pr_4033(void) {
+ void *lbl = &&next_opcode;
next_opcode:
{
Opcode op = pr_4033_getOpcode();
@@ -406,14 +407,14 @@ void test_trivial_symbolic_comparison(int *x) {
int test_trivial_symbolic_comparison_aux();
int a = test_trivial_symbolic_comparison_aux();
int b = a;
- if (a != b) {
+ if (a != b) { // expected-warning{{Both operands to '!=' always have the same value}}
int *p = 0;
*p = 0xDEADBEEF; // no-warning
}
a = a == 1;
b = b == 1;
- if (a != b) {
+ if (a != b) { // expected-warning{{Both operands to '!=' always have the same value}}
int *p = 0;
*p = 0xDEADBEEF; // no-warning
}
@@ -457,7 +458,7 @@ void rdar_7062158_2() {
// ElementRegion is created.
unsigned char test_array_index_bitwidth(const unsigned char *p) {
unsigned short i = 0;
- for (i = 0; i < 2; i++) p = &p[i];
+ for (i = 0; i < 2; i++) p = &p[i];
return p[i+1];
}
@@ -1020,3 +1021,50 @@ void pr7475_warn() {
*someStatic = 0; // expected-warning{{null pointer}}
}
+// <rdar://problem/8202272> - __imag passed non-complex should not crash
+float f0(_Complex float x) {
+ float l0 = __real x;
+ return __real l0 + __imag l0;
+}
+
+
+//===----------------------------------------------------------------------===
+// Test that we can reduce symbols to constants whether they are on the left
+// or right side of an expression.
+//===----------------------------------------------------------------------===
+
+void reduce_to_constant(int x, int y) {
+ if (x != 20)
+ return;
+
+ int a = x + y;
+ int b = y + x;
+
+ if (y == -20 && a != 0)
+ (void)*(char*)0; // no-warning
+ if (y == -20 && b != 0)
+ (void)*(char*)0; // no-warning
+}
+
+// <rdar://problem/8360854> - Test that code after a switch statement with no
+// 'case:' labels is correctly evaluated.
+void r8360854(int n) {
+ switch (n) {
+ default: ;
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{null pointer}}
+}
+
+// PR 8050 - crash in CastSizeChecker when pointee is an incomplete type
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+void *malloc(size_t);
+
+struct PR8050;
+
+void pr8050(struct PR8050 **arg)
+{
+ *arg = malloc(1);
+}
+
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 7ca22ad..8daa845 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -64,13 +64,13 @@ int f4_b() {
short array[2];
uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}}
short *p = x; // expected-warning{{incompatible integer to pointer conversion}}
-
+
// The following branch should be infeasible.
- if (!(p = &array[0])) {
+ if (!(p == &array[0])) { // expected-warning{{Both operands to '==' always have the same value}}
p = 0;
*p = 1; // no-warning
}
-
+
if (p) {
*p = 5; // no-warning
p = 0;
@@ -81,7 +81,6 @@ int f4_b() {
return 0;
}
-
int f5() {
char *s = "hello world";
@@ -280,7 +279,7 @@ void f12(HF12ITEM i, char *q) {
// Test handling of translating between integer "pointers" and back.
void f13() {
int *x = 0;
- if (((((int) x) << 2) + 1) >> 1) *x = 1; // no-warning
+ if (((((int) x) << 2) + 1) >> 1) *x = 1;
}
// PR 4759 - Attribute non-null checking by the analyzer was not correctly
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 9b48730..ed51dc6 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -71,3 +71,27 @@ void sizeof_vla(int a) {
y[5] = 5; // expected-warning{{out-of-bound}}
}
}
+
+void alloca_region(int a) {
+ if (a == 5) {
+ char *x = __builtin_alloca(a);
+ x[4] = 4; // no-warning
+ x[5] = 5; // expected-warning{{out-of-bound}}
+ }
+}
+
+int symbolic_index(int a) {
+ int x[2] = {1, 2};
+ if (a == 2) {
+ return x[a]; // expected-warning{{out-of-bound}}
+ }
+ return 0;
+}
+
+int symbolic_index2(int a) {
+ int x[2] = {1, 2};
+ if (a < 0) {
+ return x[a]; // expected-warning{{out-of-bound}}
+ }
+ return 0;
+}
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index aa866de..95faa06 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -205,7 +205,7 @@ void test_null_field(void) {
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index db49b91..7b98554 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -50,6 +50,7 @@ typedef struct _NSZone NSZone;
@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
@end
@interface NSObject <NSObject> {}
+- (id)init;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
@@ -223,3 +224,29 @@ void pr6699(int x) {
}
}
+// <rdar://problem/8261992> Idempotent operation checker false positive with ObjC ivars
+@interface R8261992 : NSObject {
+ @package int myIvar;
+}
+@end
+
+static void R8261992_ChangeMyIvar(R8261992 *tc) {
+ tc->myIvar = 5;
+}
+
+void R8261992_test(R8261992 *tc) {
+ int temp = tc->myIvar;
+ // The ivar binding for tc->myIvar gets invalidated.
+ R8261992_ChangeMyIvar(tc);
+ tc->myIvar = temp; // no-warning
+ tc = [[R8261992 alloc] init];
+ temp = tc->myIvar; // no-warning
+ // The ivar binding for tc->myIvar gets invalidated.
+ R8261992_ChangeMyIvar(tc);
+ tc->myIvar = temp;
+ [tc release]; // no-warning
+ // did we analyze this?
+ int *p = 0x0;
+ *p = 0xDEADBEEF; // expected-warning{{null}}
+}
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index c9c7d27..064165a 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1358,3 +1358,12 @@ void test_blocks_1_indirect_retain_via_call(void) {
}
@end
+// <rdar://problem/8272168> - Correcly handle Class<...> in Cocoa Conventions
+// detector.
+
+@protocol Prot_R8272168 @end
+Class <Prot_R8272168> GetAClassThatImplementsProt_R8272168();
+void r8272168() {
+ GetAClassThatImplementsProt_R8272168();
+}
+
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
new file mode 100644
index 0000000..593ba1d
--- /dev/null
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+
+// FIXME: Only the stack-address checking in Sema catches this right now, and
+// the stack analyzer doesn't handle the ImplicitCastExpr (lvalue).
+const int& g() {
+ int s;
+ return s; // expected-warning{{reference to stack memory associated with local variable 's' returned}}
+}
diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c
index 2b6a903..73bbc13 100644
--- a/test/Analysis/stream.c
+++ b/test/Analysis/stream.c
@@ -6,6 +6,8 @@ typedef struct _IO_FILE FILE;
#define SEEK_CUR 1 /* Seek from current position. */
#define SEEK_END 2 /* Seek from end of file. */
extern FILE *fopen(const char *path, const char *mode);
+extern FILE *tmpfile(void);
+extern int fclose(FILE *fp);
extern size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream);
@@ -15,21 +17,25 @@ void f1(void) {
FILE *p = fopen("foo", "r");
char buf[1024];
fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f2(void) {
FILE *p = fopen("foo", "r");
fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f3(void) {
FILE *p = fopen("foo", "r");
ftell(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f4(void) {
FILE *p = fopen("foo", "r");
rewind(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
}
void f5(void) {
@@ -38,4 +44,36 @@ void f5(void) {
return;
fseek(p, 1, SEEK_SET); // no-warning
fseek(p, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR.}}
+ fclose(p);
+}
+
+void f6(void) {
+ FILE *p = fopen("foo", "r");
+ fclose(p);
+ fclose(p); // expected-warning {{Try to close a file Descriptor already closed. Cause undefined behaviour.}}
+}
+
+void f7(void) {
+ FILE *p = tmpfile();
+ ftell(p); // expected-warning {{Stream pointer might be NULL.}}
+ fclose(p);
+}
+
+void f8(int c) {
+ FILE *p = fopen("foo.c", "r");
+ if(c)
+ return; // expected-warning {{Opened File never closed. Potential Resource leak.}}
+ fclose(p);
+}
+
+FILE *f9(void) {
+ FILE *p = fopen("foo.c", "r");
+ if (p)
+ return p; // no-warning
+ else
+ return 0;
+}
+
+void pr7831(FILE *fp) {
+ fclose(fp); // no-warning
}
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
new file mode 100644
index 0000000..35ed710
--- /dev/null
+++ b/test/Analysis/string.c
@@ -0,0 +1,240 @@
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+
+//===----------------------------------------------------------------------===
+// Declarations
+//===----------------------------------------------------------------------===
+
+// Some functions are so similar to each other that they follow the same code
+// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is
+// defined, make sure to use the variants instead to make sure they are still
+// checked by the analyzer.
+
+// Some functions are implemented as builtins. These should be #defined as
+// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
+
+// Functions that have variants and are also availabe as builtins should be
+// declared carefully! See memcpy() for an example.
+
+#ifdef USE_BUILTINS
+# define BUILTIN(f) __builtin_ ## f
+#else /* USE_BUILTINS */
+# define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+#define NULL 0
+typedef typeof(sizeof(int)) size_t;
+
+//===----------------------------------------------------------------------===
+// strlen()
+//===----------------------------------------------------------------------===
+
+#define strlen BUILTIN(strlen)
+size_t strlen(const char *s);
+
+void strlen_constant0() {
+ if (strlen("123") != 3)
+ (void)*(char*)0; // no-warning
+}
+
+void strlen_constant1() {
+ const char *a = "123";
+ if (strlen(a) != 3)
+ (void)*(char*)0; // no-warning
+}
+
+void strlen_constant2(char x) {
+ char a[] = "123";
+ if (strlen(a) != 3)
+ (void)*(char*)0; // no-warning
+ a[0] = x;
+ if (strlen(a) != 3)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+size_t strlen_null() {
+ return strlen(0); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+size_t strlen_fn() {
+ return strlen((char*)&strlen_fn); // expected-warning{{Argument to byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+}
+
+size_t strlen_nonloc() {
+label:
+ return strlen((char*)&&label); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
+}
+
+void strlen_subregion() {
+ struct two_strings { char a[2], b[2] };
+ extern void use_two_strings(struct two_strings *);
+
+ struct two_strings z;
+ use_two_strings(&z);
+
+ size_t a = strlen(z.a);
+ z.b[0] = 5;
+ size_t b = strlen(z.a);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ use_two_strings(&z);
+
+ size_t c = strlen(z.a);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern void use_string(char *);
+void strlen_argument(char *x) {
+ size_t a = strlen(x);
+ size_t b = strlen(x);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ use_string(x);
+
+ size_t c = strlen(x);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern char global_str[];
+void strlen_global() {
+ size_t a = strlen(global_str);
+ size_t b = strlen(global_str);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ // Call a function with unknown effects, which should invalidate globals.
+ use_string(0);
+
+ size_t c = strlen(global_str);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strlen_indirect(char *x) {
+ size_t a = strlen(x);
+ char *p = x;
+ char **p2 = &p;
+ size_t b = strlen(x);
+ if (a == 0 && b != 0)
+ (void)*(char*)0; // expected-warning{{never executed}}
+
+ extern void use_string_ptr(char*const*);
+ use_string_ptr(p2);
+
+ size_t c = strlen(x);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strlen_liveness(const char *x) {
+ if (strlen(x) < 5)
+ return;
+ if (strlen(x) < 5)
+ (void)*(char*)0; // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// strcpy()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __strcpy_chk BUILTIN(__strcpy_chk)
+char *__strcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen);
+
+#define strcpy(a,b) __strcpy_chk(a,b,(size_t)-1)
+
+#else /* VARIANT */
+
+#define strcpy BUILTIN(strcpy)
+char *strcpy(char *restrict s1, const char *restrict s2);
+
+#endif /* VARIANT */
+
+
+void strcpy_null_dst(char *x) {
+ strcpy(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcpy_null_src(char *x) {
+ strcpy(x, NULL); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcpy_fn(char *x) {
+ strcpy(x, (char*)&strcpy_fn); // expected-warning{{Argument to byte string function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
+}
+
+void strcpy_effects(char *x, char *y) {
+ char a = x[0];
+
+ if (strcpy(x, y) != x)
+ (void)*(char*)0; // no-warning
+
+ if (strlen(x) != strlen(y))
+ (void)*(char*)0; // no-warning
+
+ if (a != x[0])
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strcpy_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 4)
+ strcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strcpy_no_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 3)
+ strcpy(x, y); // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// stpcpy()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __stpcpy_chk BUILTIN(__stpcpy_chk)
+char *__stpcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen);
+
+#define stpcpy(a,b) __stpcpy_chk(a,b,(size_t)-1)
+
+#else /* VARIANT */
+
+#define stpcpy BUILTIN(stpcpy)
+char *stpcpy(char *restrict s1, const char *restrict s2);
+
+#endif /* VARIANT */
+
+
+void stpcpy_effect(char *x, char *y) {
+ char a = x[0];
+
+ if (stpcpy(x, y) != &x[strlen(y)])
+ (void)*(char*)0; // no-warning
+
+ if (strlen(x) != strlen(y))
+ (void)*(char*)0; // no-warning
+
+ if (a != x[0])
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void stpcpy_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 4)
+ stpcpy(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void stpcpy_no_overflow(char *y) {
+ char x[4];
+ if (strlen(y) == 3)
+ stpcpy(x, y); // no-warning
+}
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 69c1ecd..751e91b 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-check-idempotent-operations -verify %s
struct s {
int data;
@@ -42,7 +42,7 @@ void test_uninit_pos_3() {
void test_uninit_neg() {
struct TestUninit v1 = { 0, 0 };
struct TestUninit v2 = test_uninit_aux();
- test_unit_aux2(v2.x + v1.y); // no-warning
+ test_unit_aux2(v2.x + v1.y); // expected-warning{{The right operand to '+' is always 0}}
}
extern void test_uninit_struct_arg_aux(struct TestUninit arg);
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
new file mode 100644
index 0000000..0715327
--- /dev/null
+++ b/test/Analysis/unreachable-code-path.c
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -analyze -analyzer-experimental-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -verify -analyzer-opt-analyze-nested-blocks %s
+
+extern void foo(int a);
+
+// The first few tests are non-path specific - we should be able to find them
+
+void test(unsigned a) {
+ switch (a) {
+ a += 5; // expected-warning{{never executed}}
+ case 2:
+ a *= 10;
+ case 3:
+ a %= 2;
+ }
+ foo(a);
+}
+
+void test2(unsigned a) {
+ help:
+ if (a > 0)
+ return;
+ if (a == 0)
+ return;
+ foo(a); // expected-warning{{never executed}}
+ goto help;
+}
+
+void test3(unsigned a) {
+ while(1);
+ if (a > 5) { // expected-warning{{never executed}}
+ return;
+ }
+}
+
+// These next tests are path-sensitive
+
+void test4() {
+ int a = 5;
+
+ while (a > 1)
+ a -= 2;
+
+ if (a > 1) {
+ a = a + 56; // expected-warning{{never executed}}
+ }
+
+ foo(a);
+}
+
+extern void bar(char c);
+
+void test5(const char *c) {
+ foo(c[0]);
+
+ if (!c) {
+ bar(1); // expected-warning{{never executed}}
+ }
+}
+
+// These next tests are false positives and should not generate warnings
+
+void test6(const char *c) {
+ if (c) return;
+ if (!c) return;
+ __builtin_unreachable(); // no-warning
+}
+
+// Compile-time constant false positives
+#define CONSTANT 0
+enum test_enum { Off, On };
+void test7() {
+ if (CONSTANT)
+ return; // no-warning
+
+ if (sizeof(int))
+ return; // no-warning
+
+ if (Off)
+ return; // no-warning
+}
+
+void test8() {
+ static unsigned a = 0;
+
+ if (a)
+ a = 123; // no-warning
+
+ a = 5;
+}
+
+// Check for bugs where multiple statements are reported
+void test9(unsigned a) {
+ switch (a) {
+ if (a) // expected-warning{{never executed}}
+ foo(a + 5); // no-warning
+ else // no-warning
+ foo(a); // no-warning
+ case 1:
+ case 2:
+ break;
+ default:
+ break;
+ }
+}
OpenPOWER on IntegriCloud