diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-07-13 17:21:42 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-07-13 17:21:42 +0000 |
commit | 4ba675006b5a8edfc48b6a9bd3dcf54a70cc08f2 (patch) | |
tree | 48b44512b5db8ced345df4a1a56b5065cf2a14d9 /test/Analysis | |
parent | d7279c4c177bca357ef96ff1379fd9bc420bfe83 (diff) |
Notes
Diffstat (limited to 'test/Analysis')
25 files changed, 1360 insertions, 13 deletions
diff --git a/test/Analysis/PR7218.c b/test/Analysis/PR7218.c new file mode 100644 index 000000000000..635e56f053ec --- /dev/null +++ b/test/Analysis/PR7218.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s +char PR7218(char a) { + char buf[2]; + buf[0] = a; + return buf[1]; // expected-warning {{Undefined or garbage value returned to caller}} +} diff --git a/test/Analysis/additive-folding-range-constraints.c b/test/Analysis/additive-folding-range-constraints.c new file mode 100644 index 000000000000..a8ca5d2e351d --- /dev/null +++ b/test/Analysis/additive-folding-range-constraints.c @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=range %s + +// These are used to trigger warnings. +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +#define NULL ((void*)0) +#define UINT_MAX (__INT_MAX__ *2U +1U) + +// Each of these adjusted ranges has an adjustment small enough to split the +// solution range across an overflow boundary (Min for <, Max for >). +// This corresponds to one set of branches in RangeConstraintManager. +void smallAdjustmentGT (unsigned a) { + char* b = NULL; + if (a+2 > 1) + b = malloc(1); + if (a == UINT_MAX-1 || a == UINT_MAX) + return; // no-warning + else if (a < UINT_MAX-1) + free(b); + return; // no-warning +} + +void smallAdjustmentGE (unsigned a) { + char* b = NULL; + if (a+2 >= 1) + b = malloc(1); + if (a == UINT_MAX-1) + return; // no-warning + else if (a < UINT_MAX-1 || a == UINT_MAX) + free(b); + return; // no-warning +} + +void smallAdjustmentLT (unsigned a) { + char* b = NULL; + if (a+1 < 2) + b = malloc(1); + if (a == 0 || a == UINT_MAX) + free(b); + return; // no-warning +} + +void smallAdjustmentLE (unsigned a) { + char* b = NULL; + if (a+1 <= 2) + b = malloc(1); + if (a == 0 || a == 1 || a == UINT_MAX) + free(b); + return; // no-warning +} + + +// Each of these adjusted ranges has an adjustment large enough to push the +// comparison value over an overflow boundary (Min for <, Max for >). +// This corresponds to one set of branches in RangeConstraintManager. +void largeAdjustmentGT (unsigned a) { + char* b = NULL; + if (a-2 > UINT_MAX-1) + b = malloc(1); + if (a == 1 || a == 0) + free(b); + else if (a > 1) + free(b); + return; // no-warning +} + +void largeAdjustmentGE (unsigned a) { + char* b = NULL; + if (a-2 >= UINT_MAX-1) + b = malloc(1); + if (a > 1) + return; // no-warning + else if (a == 1 || a == 0) + free(b); + return; // no-warning +} + +void largeAdjustmentLT (unsigned a) { + char* b = NULL; + if (a+2 < 1) + b = malloc(1); + if (a == UINT_MAX-1 || a == UINT_MAX) + free(b); + else if (a < UINT_MAX-1) + return; // no-warning + return; // no-warning +} + +void largeAdjustmentLE (unsigned a) { + char* b = NULL; + if (a+2 <= 1) + b = malloc(1); + if (a < UINT_MAX-1) + return; // no-warning + else if (a == UINT_MAX-1 || a == UINT_MAX) + free(b); + return; // no-warning +} diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c new file mode 100644 index 000000000000..15d758800adc --- /dev/null +++ b/test/Analysis/additive-folding.c @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=basic %s +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=range %s + +// These are used to trigger warnings. +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); +#define NULL ((void*)0) +#define UINT_MAX -1U + +//--------------- +// Plus/minus +//--------------- + +void separateExpressions (int a) { + int b = a + 1; + --b; + + char* buf = malloc(1); + if (a != 0 && b == 0) + return; // no-warning + free(buf); +} + +void oneLongExpression (int a) { + // Expression canonicalization should still allow this to work, even though + // the first term is on the left. + int b = 15 + a + 15 - 10 - 20; + + char* buf = malloc(1); + if (a != 0 && b == 0) + return; // no-warning + free(buf); +} + +void mixedTypes (int a) { + char* buf = malloc(1); + + // Different additive types should not cause crashes when constant-folding. + // This is part of PR7406. + int b = a + 1LL; + if (a != 0 && (b-1) == 0) // not crash + return; // no warning + + int c = a + 1U; + if (a != 0 && (c-1) == 0) // not crash + return; // no warning + + free(buf); +} + +//--------------- +// Comparisons +//--------------- + +// Equality and inequality only +void eq_ne (unsigned a) { + char* b = NULL; + if (a == UINT_MAX) + b = malloc(1); + if (a+1 != 0) + return; // no-warning + if (a-1 != UINT_MAX-1) + return; // no-warning + free(b); +} + +void ne_eq (unsigned a) { + char* b = NULL; + if (a != UINT_MAX) + b = malloc(1); + if (a+1 == 0) + return; // no-warning + if (a-1 == UINT_MAX-1) + return; // no-warning + free(b); +} + +// Mixed typed inequalities (part of PR7406) +// These should not crash. +void mixed_eq_ne (int a) { + char* b = NULL; + if (a == 1) + b = malloc(1); + if (a+1U != 2) + return; // no-warning + if (a-1U != 0) + return; // no-warning + free(b); +} + +void mixed_ne_eq (int a) { + char* b = NULL; + if (a != 1) + b = malloc(1); + if (a+1U == 2) + return; // no-warning + if (a-1U == 0) + return; // no-warning + free(b); +} + + +// Simple order comparisons with no adjustment +void baselineGT (unsigned a) { + char* b = NULL; + if (a > 0) + b = malloc(1); + if (a == 0) + return; // no-warning + free(b); +} + +void baselineGE (unsigned a) { + char* b = NULL; + if (a >= UINT_MAX) + b = malloc(1); + if (a == UINT_MAX) + free(b); + return; // no-warning +} + +void baselineLT (unsigned a) { + char* b = NULL; + if (a < UINT_MAX) + b = malloc(1); + if (a == UINT_MAX) + return; // no-warning + free(b); +} + +void baselineLE (unsigned a) { + char* b = NULL; + if (a <= 0) + b = malloc(1); + if (a == 0) + free(b); + return; // no-warning +} + + +// Adjustment gives each of these an extra solution! +void adjustedGT (unsigned a) { + char* b = NULL; + if (a-1 > UINT_MAX-1) + b = malloc(1); + return; // expected-warning{{leak}} +} + +void adjustedGE (unsigned a) { + char* b = NULL; + if (a-1 >= UINT_MAX-1) + b = malloc(1); + if (a == UINT_MAX) + free(b); + return; // expected-warning{{leak}} +} + +void adjustedLT (unsigned a) { + char* b = NULL; + if (a+1 < 1) + b = malloc(1); + return; // expected-warning{{leak}} +} + +void adjustedLE (unsigned a) { + char* b = NULL; + if (a+1 <= 1) + b = malloc(1); + if (a == 0) + free(b); + return; // expected-warning{{leak}} +} + + +// Tautologies +void tautologyGT (unsigned a) { + char* b = malloc(1); + if (a > UINT_MAX) + return; // no-warning + free(b); +} + +void tautologyGE (unsigned a) { + char* b = malloc(1); + if (a >= 0) + free(b); + return; // no-warning +} + +void tautologyLT (unsigned a) { + char* b = malloc(1); + if (a < 0) + return; // no-warning + free(b); +} + +void tautologyLE (unsigned a) { + char* b = malloc(1); + if (a <= UINT_MAX) + free(b); + return; // no-warning +} diff --git a/test/Analysis/analyze_display_progress.c b/test/Analysis/analyze_display_progress.c new file mode 100644 index 000000000000..958ed009ff10 --- /dev/null +++ b/test/Analysis/analyze_display_progress.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s + +void f() {}; +void g() {}; +void h() {} + +// CHECK: analyze_display_progress.c f +// CHECK: analyze_display_progress.c g +// CHECK: analyze_display_progress.c h
\ No newline at end of file diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c new file mode 100644 index 000000000000..f4ddb0a3d080 --- /dev/null +++ b/test/Analysis/bstring.c @@ -0,0 +1,277 @@ +// 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 */ + +typedef typeof(sizeof(int)) size_t; + +//===----------------------------------------------------------------------=== +// memcpy() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __memcpy_chk BUILTIN(__memcpy_chk) +void *__memcpy_chk(void *restrict s1, const void *restrict s2, size_t n, + size_t destlen); + +#define memcpy(a,b,c) __memcpy_chk(a,b,c,(size_t)-1) + +#else /* VARIANT */ + +#define memcpy BUILTIN(memcpy) +void *memcpy(void *restrict s1, const void *restrict s2, size_t n); + +#endif /* VARIANT */ + + +void memcpy0 () { + char src[] = {1, 2, 3, 4}; + char dst[4]; + + memcpy(dst, src, 4); // no-warning + + if (memcpy(dst, src, 4) != dst) { + (void)*(char*)0; // no-warning -- should be unreachable + } +} + +void memcpy1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memcpy(dst, src, 5); // expected-warning{{out-of-bound}} +} + +void memcpy2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + memcpy(dst, src, 4); // expected-warning{{out-of-bound}} +} + +void memcpy3 () { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + memcpy(dst+1, src+2, 2); // no-warning +} + +void memcpy4 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memcpy(dst+2, src+2, 3); // expected-warning{{out-of-bound}} +} + +void memcpy5() { + char src[] = {1, 2, 3, 4}; + char dst[3]; + + memcpy(dst+2, src+2, 2); // expected-warning{{out-of-bound}} +} + +void memcpy6() { + int a[4] = {0}; + memcpy(a, a, 8); // expected-warning{{overlapping}} +} + +void memcpy7() { + int a[4] = {0}; + memcpy(a+2, a+1, 8); // expected-warning{{overlapping}} +} + +void memcpy8() { + int a[4] = {0}; + memcpy(a+1, a+2, 8); // expected-warning{{overlapping}} +} + +void memcpy9() { + int a[4] = {0}; + memcpy(a+2, a+1, 4); // no-warning + memcpy(a+1, a+2, 4); // no-warning +} + +void memcpy10() { + char a[4] = {0}; + memcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void memcpy11() { + char a[4] = {0}; + memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void memcpy12() { + char a[4] = {0}; + memcpy(0, a, 0); // no-warning + memcpy(a, 0, 0); // no-warning +} + +//===----------------------------------------------------------------------=== +// memmove() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define __memmove_chk BUILTIN(__memmove_chk) +void *__memmove_chk(void *s1, const void *s2, size_t n, size_t destlen); + +#define memmove(a,b,c) __memmove_chk(a,b,c,(size_t)-1) + +#else /* VARIANT */ + +#define memmove BUILTIN(memmove) +void *memmove(void *s1, const void *s2, size_t n); + +#endif /* VARIANT */ + + +void memmove0 () { + char src[] = {1, 2, 3, 4}; + char dst[4]; + + memmove(dst, src, 4); // no-warning + + if (memmove(dst, src, 4) != dst) { + (void)*(char*)0; // no-warning -- should be unreachable + } +} + +void memmove1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + memmove(dst, src, 5); // expected-warning{{out-of-bound}} +} + +void memmove2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + memmove(dst, src, 4); // expected-warning{{out-of-bound}} +} + +//===----------------------------------------------------------------------=== +// memcmp() +//===----------------------------------------------------------------------=== + +#ifdef VARIANT + +#define bcmp BUILTIN(bcmp) +// __builtin_bcmp is not defined with const in Builtins.def. +int bcmp(/*const*/ void *s1, /*const*/ void *s2, size_t n); +#define memcmp bcmp + +#else /* VARIANT */ + +#define memcmp BUILTIN(memcmp) +int memcmp(const void *s1, const void *s2, size_t n); + +#endif /* VARIANT */ + + +void memcmp0 () { + char a[] = {1, 2, 3, 4}; + char b[4] = { 0 }; + + memcmp(a, b, 4); // no-warning +} + +void memcmp1 () { + char a[] = {1, 2, 3, 4}; + char b[10] = { 0 }; + + memcmp(a, b, 5); // expected-warning{{out-of-bound}} +} + +void memcmp2 () { + char a[] = {1, 2, 3, 4}; + char b[1] = { 0 }; + + memcmp(a, b, 4); // expected-warning{{out-of-bound}} +} + +void memcmp3 () { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, a, 4)) + (void)*(char*)0; // no-warning +} + +void memcmp4 (char *input) { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, input, 4)) + (void)*(char*)0; // expected-warning{{null}} +} + +void memcmp5 (char *input) { + char a[] = {1, 2, 3, 4}; + + if (memcmp(a, 0, 0)) // no-warning + (void)*(char*)0; // no-warning + if (memcmp(0, a, 0)) // no-warning + (void)*(char*)0; // no-warning + if (memcmp(a, input, 0)) // no-warning + (void)*(char*)0; // no-warning +} + +void memcmp6 (char *a, char *b, size_t n) { + int result = memcmp(a, b, n); + if (result != 0) + return; + if (n == 0) + (void)*(char*)0; // expected-warning{{null}} +} + +//===----------------------------------------------------------------------=== +// bcopy() +//===----------------------------------------------------------------------=== + +#define bcopy BUILTIN(bcopy) +// __builtin_bcopy is not defined with const in Builtins.def. +void bcopy(/*const*/ void *s1, void *s2, size_t n); + + +void bcopy0 () { + char src[] = {1, 2, 3, 4}; + char dst[4]; + + bcopy(src, dst, 4); // no-warning +} + +void bcopy1 () { + char src[] = {1, 2, 3, 4}; + char dst[10]; + + bcopy(src, dst, 5); // expected-warning{{out-of-bound}} +} + +void bcopy2 () { + char src[] = {1, 2, 3, 4}; + char dst[1]; + + bcopy(src, dst, 4); // expected-warning{{out-of-bound}} +} diff --git a/test/Analysis/constant-folding.c b/test/Analysis/constant-folding.c new file mode 100644 index 000000000000..6ed2b390cf7a --- /dev/null +++ b/test/Analysis/constant-folding.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-experimental-checks -verify %s + +// Trigger a warning if the analyzer reaches this point in the control flow. +#define WARN ((void)*(char*)0) + +// There should be no warnings unless otherwise indicated. + +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; +} + +void testSelfOperations (int a) { + if ((a|a) != a) WARN; + if ((a&a) != a) WARN; + if ((a^a) != 0) WARN; + if ((a-a) != 0) WARN; +} + +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; +} + +void testReductionToConstant (int a) { + if ((a*0) != 0) WARN; + if ((a&0) != 0) WARN; + if ((a|(~0)) != (~0)) WARN; +} + +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; +} + +void testAsymmetricIntSymOperations (int a) { + if (((~0) >> a) != (~0)) WARN; + if ((0 >> a) != 0) WARN; + if ((0 << a) != 0) WARN; + + // Unsigned right shift shifts in zeroes. + if ((((unsigned)(~0)) >> ((unsigned) a)) != ((unsigned)(~0))) + WARN; // expected-warning{{}} +} + +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; +} diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 1c600276ba43..defd7e0b7bdf 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -300,11 +300,11 @@ void f22() { case 7: (void)(0 && x); (void)y7; - (void)(0 || (y8, ({ return; }), 1)); + (void)(0 || (y8, ({ return; }), 1)); // expected-warning {{expression result unused}} (void)x; break; case 8: - (void)(1 && (y9, ({ return; }), 1)); + (void)(1 && (y9, ({ return; }), 1)); // expected-warning {{expression result unused}} (void)x; break; case 9: diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp index 22d446e17021..b21ffad6c5f0 100644 --- a/test/Analysis/dead-stores.cpp +++ b/test/Analysis/dead-stores.cpp @@ -92,3 +92,11 @@ void test3_e(int &x) { int &y = x; } +//===----------------------------------------------------------------------===// +// Dead stores involving 'new' +//===----------------------------------------------------------------------===// + +static void test_new(unsigned n) { + char **p = new char* [n]; // expected-warning{{never read}} +} + diff --git a/test/Analysis/free.c b/test/Analysis/free.c new file mode 100644 index 000000000000..60bb3f2eb5a6 --- /dev/null +++ b/test/Analysis/free.c @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -fblocks -verify %s +void free(void *); + +void t1 () { + int a[] = { 1 }; + free(a); // expected-warning {{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}} +} + +void t2 () { + int a = 1; + free(&a); // expected-warning {{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}} +} + +void t3 () { + static int a[] = { 1 }; + free(a); // expected-warning {{Argument to free() is the address of the static variable 'a', which is not memory allocated by malloc()}} +} + +void t4 (char *x) { + free(x); // no-warning +} + +void t5 () { + extern char *ptr(); + free(ptr()); // no-warning +} + +void t6 () { + free((void*)1000); // expected-warning {{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}} +} + +void t7 (char **x) { + free(*x); // no-warning +} + +void t8 (char **x) { + // ugh + free((*x)+8); // no-warning +} + +void t9 () { +label: + free(&&label); // expected-warning {{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}} +} + +void t10 () { + free((void*)&t10); // expected-warning {{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} +} + +void t11 () { + char *p = (char*)__builtin_alloca(2); + free(p); // expected-warning {{Argument to free() was allocated by alloca(), not malloc()}} +} + +void t12 () { + free(^{return;}); // expected-warning {{Argument to free() is a block, which is not memory allocated by malloc()}} +} + +void t13 (char a) { + free(&a); // expected-warning {{Argument to free() is the address of the parameter 'a', which is not memory allocated by malloc()}} +} + +static int someGlobal[2]; +void t14 () { + free(someGlobal); // expected-warning {{Argument to free() is the address of the global variable 'someGlobal', which is not memory allocated by malloc()}} +} + +void t15 (char **x, int offset) { + // Unknown value + free(x[offset]); // no-warning +} diff --git a/test/Analysis/idempotent-operations.c b/test/Analysis/idempotent-operations.c new file mode 100644 index 000000000000..9cef08edc43f --- /dev/null +++ b/test/Analysis/idempotent-operations.c @@ -0,0 +1,52 @@ +// 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 + +// Basic tests + +extern void test(int i); + +void 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 = 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}} + 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}} + + // 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}} + + // 1 op x + test(one * x); // expected-warning {{idempotent operation; the left operand 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}} + + // 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}} +} diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index fe24bc19e61c..b4c1314b34cf 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -75,5 +75,49 @@ void PR6123() { void PR7217() { int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} buf[1] = 'c'; // not crash +} + +void mallocCastToVoid() { + void *p = malloc(2); + const void *cp = p; // not crash + free(p); +} + +void mallocCastToFP() { + void *p = malloc(2); + void (*fp)() = p; // not crash + free(p); +} + +// This tests that malloc() buffers are undefined by default +char mallocGarbage () { + char *buf = malloc(2); + char result = buf[1]; // expected-warning{{undefined}} + free(buf); + return result; +} + +// This tests that calloc() buffers need to be freed +void callocNoFree () { + char *buf = calloc(2,2); + return; // expected-warning{{never released}} +} + +// These test that calloc() buffers are zeroed by default +char callocZeroesGood () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] == 0) { + free(buf); + } + return result; // no-warning +} +char callocZeroesBad () { + char *buf = calloc(2,2); + char result = buf[3]; // no-warning + if (buf[1] != 0) { + free(buf); + } + return result; // expected-warning{{never released}} } diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index 52516abc397b..6b4f658a3f85 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -1033,3 +1033,11 @@ double rdar_8032791_1() { return x; } +// PR 7450 - Handle pointer arithmetic with __builtin_alloca +void pr_7450_aux(void *x); +void pr_7450() { + void *p = __builtin_alloca(10); + // Don't crash when analyzing the following statement. + pr_7450_aux(p + 8); +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 8323c62390e8..b1d47e214ef7 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -582,7 +582,7 @@ void pr4781(unsigned long *raw1) { - (id) foo { if (self) return self; - *((int *) 0x0) = 0xDEADBEEF; // no-warning + *((volatile int *) 0x0) = 0xDEADBEEF; // no-warning return self; } @end @@ -971,3 +971,52 @@ void r7979430(id x) { @synchronized(x) {} } +//===----------------------------------------------------------------------=== +// PR 7361 - Test that functions wrapped in macro instantiations are analyzed. +//===----------------------------------------------------------------------=== +#define MAKE_TEST_FN() \ + void test_pr7361 (char a) {\ + char* b = 0x0; *b = a;\ + } + +MAKE_TEST_FN() // expected-warning{{null pointer}} + +//===----------------------------------------------------------------------=== +// PR 7491 - Test that symbolic expressions can be used as conditions. +//===----------------------------------------------------------------------=== + +void pr7491 () { + extern int getint(); + int a = getint()-1; + if (a) { + return; + } + if (!a) { + return; + } else { + // Should be unreachable + (void)*(char*)0; // no-warning + } +} + +//===----------------------------------------------------------------------=== +// PR 7475 - Test that assumptions about global variables are reset after +// calling a global function. +//===----------------------------------------------------------------------=== + +int *pr7475_someGlobal; +void pr7475_setUpGlobal(); + +void pr7475() { + if (pr7475_someGlobal == 0) + pr7475_setUpGlobal(); + *pr7475_someGlobal = 0; // no-warning +} + +void pr7475_warn() { + static int *someStatic = 0; + if (someStatic == 0) + pr7475_setUpGlobal(); + *someStatic = 0; // expected-warning{{null pointer}} +} + diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c index 771323b81114..a97b68e2d6df 100644 --- a/test/Analysis/no-outofbounds.c +++ b/test/Analysis/no-outofbounds.c @@ -12,3 +12,20 @@ void f() { short *z = (short*) &x; short s = z[0] + z[1]; // no-warning } + +void g() { + int a[2]; + char *b = (char*)a; + b[3] = 'c'; // no-warning +} + +typedef typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +void field() { + struct vec { size_t len; int data[0]; }; + struct vec *a = malloc(sizeof(struct vec) + 10); + a->len = 10; + a->data[1] = 5; // no-warning +} diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c index 5a1049c7d71e..7ca22ada7da7 100644 --- a/test/Analysis/null-deref-ps.c +++ b/test/Analysis/null-deref-ps.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic -Wreturn-type +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic -Wreturn-type +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -Wreturn-type +// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type typedef unsigned uintptr_t; @@ -118,6 +118,11 @@ void f6d(int *p) { } } +void f6e(int *p, int offset) { + // PR7406 - crash from treating an UnknownVal as defined, to see if it's 0. + bar((p+offset)+1, 0); // not crash +} + int* qux(); int f7(int x) { diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c index e1ff66ccf4dc..9b487300c88a 100644 --- a/test/Analysis/outofbound.c +++ b/test/Analysis/outofbound.c @@ -2,6 +2,7 @@ typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); +void *calloc(size_t, size_t); char f1() { char* s = "abcd"; @@ -36,3 +37,37 @@ void f4() { p[1] = a; // no-warning p[2] = a; // expected-warning{{Access out-of-bound array element (buffer overflow)}} } + +void f5() { + char *p = calloc(2,2); + p[3] = '.'; // no-warning + p[4] = '!'; // expected-warning{{out-of-bound}} +} + +void f6() { + char a[2]; + int *b = (int*)a; + b[1] = 3; // expected-warning{{out-of-bound}} +} + +void f7() { + struct three_words a; + a.c[3] = 1; // expected-warning{{out-of-bound}} +} + +void vla(int a) { + if (a == 5) { + int x[a]; + x[4] = 4; // no-warning + x[5] = 5; // expected-warning{{out-of-bound}} + } +} + +void sizeof_vla(int a) { + if (a == 5) { + char x[a]; + int y[sizeof(x)]; + y[4] = 4; // no-warning + y[5] = 5; // expected-warning{{out-of-bound}} + } +} diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c index f6bd61c074a3..0c2e22139821 100644 --- a/test/Analysis/ptr-arith.c +++ b/test/Analysis/ptr-arith.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s // RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -triple i686-apple-darwin9 %s +// Used to trigger warnings for unreachable paths. +#define WARN do { int a, b; int c = &b-&a; } while (0) + void f1() { int a[10]; int *p = a; @@ -60,3 +63,226 @@ void f5() { void f6(int *p, int *q) { int d = q - p; // no-warning } + +void null_operand(int *a) { +start: + // LHS is a label, RHS is NULL + if (&&start == 0) + WARN; // no-warning + if (&&start < 0) + WARN; // no-warning + if (&&start <= 0) + WARN; // no-warning + if (!(&&start != 0)) + WARN; // no-warning + if (!(&&start > 0)) + WARN; // no-warning + if (!(&&start >= 0)) + WARN; // no-warning + if (!(&&start - 0)) + WARN; // no-warning + + // LHS is a non-symbolic value, RHS is NULL + if (&a == 0) + WARN; // no-warning + if (&a < 0) + WARN; // no-warning + if (&a <= 0) + WARN; // no-warning + if (!(&a != 0)) + WARN; // no-warning + if (!(&a > 0)) + WARN; // no-warning + if (!(&a >= 0)) + WARN; // no-warning + + if (!(&a - 0)) // expected-warning{{Pointer arithmetic done on non-array variables}} + WARN; // no-warning + + // LHS is NULL, RHS is non-symbolic + // The same code is used for labels and non-symbolic values. + if (0 == &a) + WARN; // no-warning + if (0 > &a) + WARN; // no-warning + if (0 >= &a) + WARN; // no-warning + if (!(0 != &a)) + WARN; // no-warning + if (!(0 < &a)) + WARN; // no-warning + if (!(0 <= &a)) + WARN; // no-warning + + // LHS is a symbolic value, RHS is NULL + if (a == 0) + WARN; // expected-warning{{}} + if (a < 0) + WARN; // no-warning + if (a <= 0) + WARN; // expected-warning{{}} + if (!(a != 0)) + WARN; // expected-warning{{}} + if (!(a > 0)) + WARN; // expected-warning{{}} + if (!(a >= 0)) + WARN; // no-warning + if (!(a - 0)) + WARN; // expected-warning{{}} + + // LHS is NULL, RHS is a symbolic value + if (0 == a) + WARN; // expected-warning{{}} + if (0 > a) + WARN; // no-warning + if (0 >= a) + WARN; // expected-warning{{}} + if (!(0 != a)) + WARN; // expected-warning{{}} + if (!(0 < a)) + WARN; // expected-warning{{}} + if (!(0 <= a)) + WARN; // no-warning +} + +void const_locs() { + char *a = (char*)0x1000; + char *b = (char*)0x1100; +start: + if (a==b) + WARN; // no-warning + if (!(a!=b)) + WARN; // no-warning + if (a>b) + WARN; // no-warning + if (b<a) + WARN; // no-warning + if (a>=b) + WARN; // no-warning + if (b<=a) + WARN; // no-warning + if (b-a != 0x100) + WARN; // no-warning + + if (&&start == a) + WARN; // expected-warning{{}} + if (a == &&start) + WARN; // expected-warning{{}} + if (&a == (char**)a) + WARN; // expected-warning{{}} + if ((char**)a == &a) + WARN; // expected-warning{{}} +} + +void array_matching_types() { + int array[10]; + int *a = &array[2]; + int *b = &array[5]; + + if (a==b) + WARN; // no-warning + if (!(a!=b)) + WARN; // no-warning + if (a>b) + WARN; // no-warning + if (b<a) + WARN; // no-warning + if (a>=b) + WARN; // no-warning + if (b<=a) + WARN; // no-warning + if ((b-a) == 0) + WARN; // no-warning +} + +// This takes a different code path than array_matching_types() +void array_different_types() { + int array[10]; + int *a = &array[2]; + char *b = (char*)&array[5]; + + if (a==b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (!(a!=b)) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (a>b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (b<a) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (a>=b) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning + if (b<=a) // expected-warning{{comparison of distinct pointer types}} + WARN; // no-warning +} + +struct test { int x; int y; }; +void struct_fields() { + struct test a, b; + + if (&a.x == &a.y) + WARN; // no-warning + if (!(&a.x != &a.y)) + WARN; // no-warning + if (&a.x > &a.y) + WARN; // no-warning + if (&a.y < &a.x) + WARN; // no-warning + if (&a.x >= &a.y) + WARN; // no-warning + if (&a.y <= &a.x) + WARN; // no-warning + + if (&a.x == &b.x) + WARN; // no-warning + if (!(&a.x != &b.x)) + WARN; // no-warning + if (&a.x > &b.x) + WARN; // expected-warning{{}} + if (&b.x < &a.x) + WARN; // expected-warning{{}} + if (&a.x >= &b.x) + WARN; // expected-warning{{}} + if (&b.x <= &a.x) + WARN; // expected-warning{{}} +} + +void mixed_region_types() { + struct test s; + int array[2]; + void *a = &array, *b = &s; + + if (&a == &b) + WARN; // no-warning + if (!(&a != &b)) + WARN; // no-warning + if (&a > &b) + WARN; // expected-warning{{}} + if (&b < &a) + WARN; // expected-warning{{}} + if (&a >= &b) + WARN; // expected-warning{{}} + if (&b <= &a) + WARN; // expected-warning{{}} +} + +void symbolic_region(int *p) { + int a; + + if (&a == p) + WARN; // expected-warning{{}} + if (&a != p) + WARN; // expected-warning{{}} + if (&a > p) + WARN; // expected-warning{{}} + if (&a < p) + WARN; // expected-warning{{}} + if (&a >= p) + WARN; // expected-warning{{}} + if (&a <= p) + WARN; // expected-warning{{}} +} + +void PR7527 (int *p) { + if (((int) p) & 1) // not crash + return; +} diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m index a2af94637d0e..dfe9b722d13f 100644 --- a/test/Analysis/rdar-6442306-1.m +++ b/test/Analysis/rdar-6442306-1.m @@ -10,7 +10,7 @@ struct QuxSize {}; typedef struct QuxSize QuxSize; typedef struct { Foo_record_t Foo; - QuxSize size; + QuxSize size[0]; } __Request__SetPortalSize_t; double __Foo_READSWAP__double(double*); diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m index bb34713b41f6..5a7b08584f57 100644 --- a/test/Analysis/rdar-7168531.m +++ b/test/Analysis/rdar-7168531.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=region -// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=basic +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=region %s +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=basic %s // Note that the target triple is important for this test case. It specifies that we use the // fragile Objective-C ABI. diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp index 54d7cf57e0c4..f1694163a20c 100644 --- a/test/Analysis/reference.cpp +++ b/test/Analysis/reference.cpp @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s +typedef typeof(sizeof(int)) size_t; +void malloc (size_t); void f1() { int const &i = 3; @@ -9,3 +11,46 @@ void f1() { if (b != 3) *p = 1; // no-warning } + +char* ptr(); +char& ref(); + +// These next two tests just shouldn't crash. +char t1 () { + ref() = 'c'; + return '0'; +} + +// just a sanity test, the same behavior as t1() +char t2 () { + *ptr() = 'c'; + return '0'; +} + +// Each of the tests below is repeated with pointers as well as references. +// This is mostly a sanity check, but then again, both should work! +char t3 () { + char& r = ref(); + r = 'c'; // no-warning + if (r) return r; + return *(char*)0; // no-warning +} + +char t4 () { + char* p = ptr(); + *p = 'c'; // no-warning + if (*p) return *p; + return *(char*)0; // no-warning +} + +char t5 (char& r) { + r = 'c'; // no-warning + if (r) return r; + return *(char*)0; // no-warning +} + +char t6 (char* p) { + *p = 'c'; // no-warning + if (*p) return *p; + return *(char*)0; // no-warning +} diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index 9e5151d16704..c9c7d271347b 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -468,6 +468,20 @@ void f16(int x, CFTypeRef p) { } } +// Test that an object is non-null after being CFRetained/CFReleased. +void f17(int x, CFTypeRef p) { + if (x) { + CFRelease(p); + if (!p) + CFRelease(0); // no-warning + } + else { + CFRetain(p); + if (!p) + CFRetain(0); // no-warning + } +} + // Test basic tracking of ivars associated with 'self'. For the retain/release // checker we currently do not want to flag leaks associated with stores // of tracked objects to ivars. diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c index f8cadbe281be..342b3b1430a2 100644 --- a/test/Analysis/stack-addr-ps.c +++ b/test/Analysis/stack-addr-ps.c @@ -3,11 +3,11 @@ int* f1() { int x = 0; - return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned.}} expected-warning{{address of stack memory associated with local variable 'x' returned}} + return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned}} expected-warning{{address of stack memory associated with local variable 'x' returned}} } int* f2(int y) { - return &y; // expected-warning{{Address of stack memory associated with local variable 'y' returned.}} expected-warning{{address of stack memory associated with local variable 'y' returned}} + return &y; // expected-warning{{Address of stack memory associated with local variable 'y' returned}} expected-warning{{address of stack memory associated with local variable 'y' returned}} } int* f3(int x, int *y) { @@ -16,7 +16,7 @@ int* f3(int x, int *y) { if (x) y = &w; - return y; // expected-warning{{Address of stack memory associated with local variable 'w' returned.}} + return y; // expected-warning{{Address of stack memory associated with local variable 'w' returned to caller}} } void* compound_literal(int x, int y) { diff --git a/test/Analysis/stackaddrleak.c b/test/Analysis/stackaddrleak.c new file mode 100644 index 000000000000..39808ed873c8 --- /dev/null +++ b/test/Analysis/stackaddrleak.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s + +char const *p; + +void f0() { + char const str[] = "This will change"; + p = str; // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}} +} + +void f1() { + char const str[] = "This will change"; + p = str; + p = 0; // no-warning +} + +void f2() { + p = (const char *) __builtin_alloca(12); // expected-warning{{Address of stack memory allocated by call to alloca() on line 17 is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}} +} + +// PR 7383 - previosly the stack address checker would crash on this example +// because it would attempt to do a direct load from 'pr7383_list'. +static int pr7383(__const char *__) +{ + return 0; +} +extern __const char *__const pr7383_list[]; + +// Test that we catch multiple returns via globals when analyzing a function. +void test_multi_return() { + static int *a, *b; + int x; + a = &x; + b = &x; // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'a' upon returning}} expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'b' upon returning}} +} diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c new file mode 100644 index 000000000000..2b6a90353b9b --- /dev/null +++ b/test/Analysis/stream.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store region -verify %s + +typedef __typeof__(sizeof(int)) size_t; +typedef struct _IO_FILE FILE; +#define SEEK_SET 0 /* Seek from beginning of 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 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); +extern void rewind (FILE *__stream); + +void f1(void) { + FILE *p = fopen("foo", "r"); + char buf[1024]; + fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL.}} +} + +void f2(void) { + FILE *p = fopen("foo", "r"); + fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL.}} +} + +void f3(void) { + FILE *p = fopen("foo", "r"); + ftell(p); // expected-warning {{Stream pointer might be NULL.}} +} + +void f4(void) { + FILE *p = fopen("foo", "r"); + rewind(p); // expected-warning {{Stream pointer might be NULL.}} +} + +void f5(void) { + FILE *p = fopen("foo", "r"); + if (!p) + 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.}} +} diff --git a/test/Analysis/undef-buffers.c b/test/Analysis/undef-buffers.c new file mode 100644 index 000000000000..4c5beb320ac9 --- /dev/null +++ b/test/Analysis/undef-buffers.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +char stackBased1 () { + char buf[2]; + buf[0] = 'a'; + return buf[1]; // expected-warning{{Undefined}} +} + +char stackBased2 () { + char buf[2]; + buf[1] = 'a'; + return buf[0]; // expected-warning{{Undefined}} +} + +char heapBased1 () { + char *buf = malloc(2); + buf[0] = 'a'; + char result = buf[1]; // expected-warning{{undefined}} + free(buf); + return result; +} + +char heapBased2 () { + char *buf = malloc(2); + buf[1] = 'a'; + char result = buf[0]; // expected-warning{{undefined}} + free(buf); + return result; +} |