// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring.NullArg,experimental.unix.cstring.OutOfBounds,experimental.unix.cstring.BufferOverlap,experimental.unix.cstring.NotNullTerminated -analyzer-store=region -Wno-null-dereference -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 available 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] = {0};
memcpy(dst, src, 4); // no-warning
if (memcpy(dst, src, 4) != dst) {
(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{{Memory copy function accesses out-of-bound array element}}
}
void memcpy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
memcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
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{{Memory copy 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{{Memory copy function overflows destination buffer}}
}
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 memory copy function}}
}
void memcpy11() {
char a[4] = {0};
memcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void memcpy12() {
char a[4] = {0};
memcpy(0, a, 0); // no-warning
}
void memcpy13() {
char a[4] = {0};
memcpy(a, 0, 0); // no-warning
}
void memcpy_unknown_size (size_t n) {
char a[4], b[4] = {1};
if (memcpy(a, b, n) != a)
(void)*(char*)0; // no-warning
}
void memcpy_unknown_size_warn (size_t n) {
char a[4];
if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
//===----------------------------------------------------------------------===
// mempcpy()
//===----------------------------------------------------------------------===
#ifdef VARIANT
#define __mempcpy_chk BUILTIN(__mempcpy_chk)
void *__mempcpy_chk(void *restrict s1, const void *restrict s2, size_t n,
size_t destlen);
#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1)
#else /* VARIANT */
#define mempcpy BUILTIN(mempcpy)
void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);
#endif /* VARIANT */
void mempcpy0 () {
char src[] = {1, 2, 3, 4};
char dst[5] = {0};
mempcpy(dst, src, 4); // no-warning
if (mempcpy(dst, src, 4) != &dst[4]) {
(void)*(char*)0; // no-warning
}
if (dst[0] != 0)
(void)*(char*)0; // expected-warning{{null}}
}
void mempcpy1 () {
char src[] = {1, 2, 3, 4};
char dst[10];
mempcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void mempcpy2 () {
char src[] = {1, 2, 3, 4};
char dst[1];
mempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy3 () {
char src[] = {1, 2, 3, 4};
char dst[3];
mempcpy(dst+1, src+2, 2); // no-warning
}
void mempcpy4 () {
char src[] = {1, 2, 3, 4};
char dst[10];
mempcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}}
}
void mempcpy5() {
char src[] = {1, 2, 3, 4};
char dst[3];
mempcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
}
void mempcpy6() {
int a[4] = {0};
mempcpy(a, a, 8); // expected-warning{{overlapping}}
}
void mempcpy7() {
int a[4] = {0};
mempcpy(a+2, a+1, 8); // expected-warning{{overlapping}}
}
void mempcpy8() {
int a[4] = {0};
mempcpy(a+1, a+2, 8); // expected-warning{{overlapping}}
}
void mempcpy9() {
int a[4] = {0};
mempcpy(a+2, a+1, 4); // no-warning
mempcpy(a+1, a+2, 4); // no-warning
}
void mempcpy10() {
char a[4] = {0};
mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void mempcpy11() {
char a[4] = {0};
mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to memory copy function}}
}
void mempcpy12() {
char a[4] = {0};
mempcpy(0, a, 0); // no-warning
}
void mempcpy13() {
char a[4] = {0};
mempcpy(a, 0, 0); // no-warning
}
void mempcpy_unknown_size_warn (size_t n) {
char a[4];
if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to memory copy function}}
(void)*(char*)0; // no-warning
}
void mempcpy_unknownable_size (char *src, float n) {
char a[4];
// This used to crash because we don't model floats.
mempcpy(a, src, (size_t)n);
}
//===----------------------------------------------------------------------===
// 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] = {0};
memmove(dst, src, 4); // no-warning
if (memmove(dst, src, 4) != dst) {
(void)*(char*)0; // no-warning
}
if (dst[0] != 0)
(void)*(char*)0; // expected-warning{{null}}
}
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{{overflow}}
}
//===----------------------------------------------------------------------===
// 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}}
}
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()
//===----------------------------------------------------------------------===
#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] = {0};
bcopy(src, dst, 4); // no-warning
if (dst[0] != 0)
(void)*(char*)0; // expected-warning{{null}}
}
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{{overflow}}
}