dejagnu-gtest.h: Add multiple inclusion guards.
* g++.dg/asan/dejagnu-gtest.h: Add multiple inclusion guards. * asan_globals_test-wrapper.cc: New file. * g++.dg/asan/asan_test.C: Use asan_globals_test-wrapper.cc instead of asan_globals_test.cc as dg-additional-sources. Include asan_mem_test.cc, asan_str_test.cc and asan_oob_test.cc. * g++.dg/asan/asan_test_utils.h: Synced from upstream. Include "sanitizer_test_utils.h" instead of "sanitizer_common/tests/sanitizer_test_utils.h". * g++.dg/asan/asan_str_test.cc: New file, synced from upstream. * g++.dg/asan/asan_mem_test.cc: New file, synced from upstream. * g++.dg/asan/asan_oob_test.cc: New file, synced from upstream. * g++.dg/asan/asan_globals_test.cc: Synced from upstream. * g++.dg/asan/asan_test.cc: Synced from upstream. * g++.dg/asan/sanitizer_test_utils.h: New file, synced from upstream. From-SVN: r196045
This commit is contained in:
parent
8fb067263b
commit
3b0c732405
@ -1,3 +1,20 @@
|
||||
2013-02-14 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* g++.dg/asan/dejagnu-gtest.h: Add multiple inclusion guards.
|
||||
* asan_globals_test-wrapper.cc: New file.
|
||||
* g++.dg/asan/asan_test.C: Use asan_globals_test-wrapper.cc
|
||||
instead of asan_globals_test.cc as dg-additional-sources.
|
||||
Include asan_mem_test.cc, asan_str_test.cc and asan_oob_test.cc.
|
||||
* g++.dg/asan/asan_test_utils.h: Synced from upstream. Include
|
||||
"sanitizer_test_utils.h" instead of
|
||||
"sanitizer_common/tests/sanitizer_test_utils.h".
|
||||
* g++.dg/asan/asan_str_test.cc: New file, synced from upstream.
|
||||
* g++.dg/asan/asan_mem_test.cc: New file, synced from upstream.
|
||||
* g++.dg/asan/asan_oob_test.cc: New file, synced from upstream.
|
||||
* g++.dg/asan/asan_globals_test.cc: Synced from upstream.
|
||||
* g++.dg/asan/asan_test.cc: Synced from upstream.
|
||||
* g++.dg/asan/sanitizer_test_utils.h: New file, synced from upstream.
|
||||
|
||||
2013-02-14 Dodji Seketeli <dodji@redhat.com>
|
||||
|
||||
Fix an asan crash
|
||||
|
2
gcc/testsuite/g++.dg/asan/asan_globals_test-wrapper.cc
Normal file
2
gcc/testsuite/g++.dg/asan/asan_globals_test-wrapper.cc
Normal file
@ -0,0 +1,2 @@
|
||||
#define DEJAGNU_GTEST_H 1
|
||||
#include "asan_globals_test.cc"
|
@ -9,8 +9,29 @@
|
||||
//
|
||||
// Some globals in a separate file.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
char glob1[1];
|
||||
char glob2[2];
|
||||
char glob3[3];
|
||||
char glob4[4];
|
||||
char glob5[5];
|
||||
char glob6[6];
|
||||
char glob7[7];
|
||||
char glob8[8];
|
||||
char glob9[9];
|
||||
char glob10[10];
|
||||
char glob11[11];
|
||||
char glob12[12];
|
||||
char glob13[13];
|
||||
char glob14[14];
|
||||
char glob15[15];
|
||||
char glob16[16];
|
||||
char glob17[17];
|
||||
char glob1000[1000];
|
||||
char glob10000[10000];
|
||||
char glob100000[100000];
|
||||
|
||||
extern char glob5[5];
|
||||
static char static10[10];
|
||||
|
||||
int GlobalsTest(int zero) {
|
||||
|
231
gcc/testsuite/g++.dg/asan/asan_mem_test.cc
Normal file
231
gcc/testsuite/g++.dg/asan/asan_mem_test.cc
Normal file
@ -0,0 +1,231 @@
|
||||
//===-- asan_mem_test.cc --------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
template<typename T>
|
||||
void MemSetOOBTestTemplate(size_t length) {
|
||||
if (length == 0) return;
|
||||
size_t size = Ident(sizeof(T) * length);
|
||||
T *array = Ident((T*)malloc(size));
|
||||
int element = Ident(42);
|
||||
int zero = Ident(0);
|
||||
void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
|
||||
// memset interval inside array
|
||||
MEMSET(array, element, size);
|
||||
MEMSET(array, element, size - 1);
|
||||
MEMSET(array + length - 1, element, sizeof(T));
|
||||
MEMSET(array, element, 1);
|
||||
|
||||
// memset 0 bytes
|
||||
MEMSET(array - 10, element, zero);
|
||||
MEMSET(array - 1, element, zero);
|
||||
MEMSET(array, element, zero);
|
||||
MEMSET(array + length, 0, zero);
|
||||
MEMSET(array + length + 1, 0, zero);
|
||||
|
||||
// try to memset bytes to the right of array
|
||||
EXPECT_DEATH(MEMSET(array, 0, size + 1),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
|
||||
RightOOBWriteMessage(0));
|
||||
// whole interval is to the right
|
||||
EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
|
||||
RightOOBWriteMessage(sizeof(T)));
|
||||
|
||||
// try to memset bytes to the left of array
|
||||
EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
|
||||
LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
|
||||
LeftOOBWriteMessage(5));
|
||||
if (length >= 100) {
|
||||
// Large OOB, we find it only if the redzone is large enough.
|
||||
EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
|
||||
LeftOOBWriteMessage(5 * sizeof(T)));
|
||||
}
|
||||
// whole interval is to the left
|
||||
EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
|
||||
LeftOOBWriteMessage(2 * sizeof(T)));
|
||||
|
||||
// try to memset bytes both to the left & to the right
|
||||
EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
|
||||
LeftOOBWriteMessage(2));
|
||||
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, MemSetOOBTest) {
|
||||
MemSetOOBTestTemplate<char>(100);
|
||||
MemSetOOBTestTemplate<int>(5);
|
||||
MemSetOOBTestTemplate<double>(256);
|
||||
// We can test arrays of structres/classes here, but what for?
|
||||
}
|
||||
|
||||
// Try to allocate two arrays of 'size' bytes that are near each other.
|
||||
// Strictly speaking we are not guaranteed to find such two pointers,
|
||||
// but given the structure of asan's allocator we will.
|
||||
static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
|
||||
vector<char *> v;
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < 1000U && !res; i++) {
|
||||
v.push_back(new char[size]);
|
||||
if (i == 0) continue;
|
||||
sort(v.begin(), v.end());
|
||||
for (size_t j = 1; j < v.size(); j++) {
|
||||
assert(v[j] > v[j-1]);
|
||||
if ((size_t)(v[j] - v[j-1]) < size * 2) {
|
||||
*x2 = v[j];
|
||||
*x1 = v[j-1];
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if (res && v[i] == *x1) continue;
|
||||
if (res && v[i] == *x2) continue;
|
||||
delete [] v[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, LargeOOBInMemset) {
|
||||
for (size_t size = 200; size < 100000; size += size / 2) {
|
||||
char *x1, *x2;
|
||||
if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
|
||||
continue;
|
||||
// fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
|
||||
// Do a memset on x1 with huge out-of-bound access that will end up in x2.
|
||||
EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
|
||||
"is located 0 bytes to the right");
|
||||
delete [] x1;
|
||||
delete [] x2;
|
||||
return;
|
||||
}
|
||||
assert(0 && "Did not find two adjacent malloc-ed pointers");
|
||||
}
|
||||
|
||||
// Same test for memcpy and memmove functions
|
||||
template <typename T, class M>
|
||||
void MemTransferOOBTestTemplate(size_t length) {
|
||||
if (length == 0) return;
|
||||
size_t size = Ident(sizeof(T) * length);
|
||||
T *src = Ident((T*)malloc(size));
|
||||
T *dest = Ident((T*)malloc(size));
|
||||
int zero = Ident(0);
|
||||
|
||||
// valid transfer of bytes between arrays
|
||||
M::transfer(dest, src, size);
|
||||
M::transfer(dest + 1, src, size - sizeof(T));
|
||||
M::transfer(dest, src + length - 1, sizeof(T));
|
||||
M::transfer(dest, src, 1);
|
||||
|
||||
// transfer zero bytes
|
||||
M::transfer(dest - 1, src, 0);
|
||||
M::transfer(dest + length, src, zero);
|
||||
M::transfer(dest, src - 1, zero);
|
||||
M::transfer(dest, src, zero);
|
||||
|
||||
// try to change mem to the right of dest
|
||||
EXPECT_DEATH(M::transfer(dest + 1, src, size),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
|
||||
RightOOBWriteMessage(0));
|
||||
|
||||
// try to change mem to the left of dest
|
||||
EXPECT_DEATH(M::transfer(dest - 2, src, size),
|
||||
LeftOOBWriteMessage(2 * sizeof(T)));
|
||||
EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
|
||||
LeftOOBWriteMessage(3));
|
||||
|
||||
// try to access mem to the right of src
|
||||
EXPECT_DEATH(M::transfer(dest, src + 2, size),
|
||||
RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
|
||||
RightOOBReadMessage(0));
|
||||
|
||||
// try to access mem to the left of src
|
||||
EXPECT_DEATH(M::transfer(dest, src - 1, size),
|
||||
LeftOOBReadMessage(sizeof(T)));
|
||||
EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
|
||||
LeftOOBReadMessage(6));
|
||||
|
||||
// Generally we don't need to test cases where both accessing src and writing
|
||||
// to dest address to poisoned memory.
|
||||
|
||||
T *big_src = Ident((T*)malloc(size * 2));
|
||||
T *big_dest = Ident((T*)malloc(size * 2));
|
||||
// try to change mem to both sides of dest
|
||||
EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
|
||||
LeftOOBWriteMessage(sizeof(T)));
|
||||
// try to access mem to both sides of src
|
||||
EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
|
||||
LeftOOBReadMessage(2 * sizeof(T)));
|
||||
|
||||
free(src);
|
||||
free(dest);
|
||||
free(big_src);
|
||||
free(big_dest);
|
||||
}
|
||||
|
||||
class MemCpyWrapper {
|
||||
public:
|
||||
static void* transfer(void *to, const void *from, size_t size) {
|
||||
return Ident(memcpy)(to, from, size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(AddressSanitizer, MemCpyOOBTest) {
|
||||
MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
|
||||
MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
|
||||
}
|
||||
|
||||
class MemMoveWrapper {
|
||||
public:
|
||||
static void* transfer(void *to, const void *from, size_t size) {
|
||||
return Ident(memmove)(to, from, size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(AddressSanitizer, MemMoveOOBTest) {
|
||||
MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
|
||||
MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
|
||||
}
|
||||
|
||||
|
||||
TEST(AddressSanitizer, MemCmpOOBTest) {
|
||||
size_t size = Ident(100);
|
||||
char *s1 = MallocAndMemsetString(size);
|
||||
char *s2 = MallocAndMemsetString(size);
|
||||
// Normal memcmp calls.
|
||||
Ident(memcmp(s1, s2, size));
|
||||
Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
|
||||
Ident(memcmp(s1 - 1, s2 - 1, 0));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
// Zero bytes are not terminators and don't prevent from OOB.
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
|
||||
|
126
gcc/testsuite/g++.dg/asan/asan_oob_test.cc
Normal file
126
gcc/testsuite/g++.dg/asan/asan_oob_test.cc
Normal file
@ -0,0 +1,126 @@
|
||||
//===-- asan_oob_test.cc --------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
|
||||
EXPECT_EQ(0U, ((uintptr_t)p % size));
|
||||
if (size == 1) asan_write((uint8_t*)p);
|
||||
else if (size == 2) asan_write((uint16_t*)p);
|
||||
else if (size == 4) asan_write((uint32_t*)p);
|
||||
else if (size == 8) asan_write((uint64_t*)p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
NOINLINE void oob_test(int size, int off) {
|
||||
char *p = (char*)malloc_aaa(size);
|
||||
// fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
|
||||
// sizeof(T), p, p + size, off);
|
||||
asan_write((T*)(p + off));
|
||||
free_aaa(p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void OOBTest() {
|
||||
char expected_str[100];
|
||||
for (int size = sizeof(T); size < 20; size += 5) {
|
||||
for (int i = -5; i < 0; i++) {
|
||||
const char *str =
|
||||
"is located.*%d byte.*to the left";
|
||||
sprintf(expected_str, str, abs(i));
|
||||
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
|
||||
oob_test<T>(size, i);
|
||||
|
||||
for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
|
||||
const char *str =
|
||||
"is located.*%d byte.*to the right";
|
||||
int off = i >= size ? (i - size) : 0;
|
||||
// we don't catch unaligned partially OOB accesses.
|
||||
if (i % sizeof(T)) continue;
|
||||
sprintf(expected_str, str, off);
|
||||
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
|
||||
"is located.*1 byte.*to the left");
|
||||
EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
|
||||
"is located.*0 byte.*to the right");
|
||||
}
|
||||
|
||||
// TODO(glider): the following tests are EXTREMELY slow on Darwin:
|
||||
// AddressSanitizer.OOB_char (125503 ms)
|
||||
// AddressSanitizer.OOB_int (126890 ms)
|
||||
// AddressSanitizer.OOBRightTest (315605 ms)
|
||||
// AddressSanitizer.SimpleStackTest (366559 ms)
|
||||
|
||||
TEST(AddressSanitizer, OOB_char) {
|
||||
OOBTest<U1>();
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, OOB_int) {
|
||||
OOBTest<U4>();
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, OOBRightTest) {
|
||||
for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
|
||||
for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
|
||||
for (size_t offset = 0; offset <= 8; offset += access_size) {
|
||||
void *p = malloc(alloc_size);
|
||||
// allocated: [p, p + alloc_size)
|
||||
// accessed: [p + offset, p + offset + access_size)
|
||||
uint8_t *addr = (uint8_t*)p + offset;
|
||||
if (offset + access_size <= alloc_size) {
|
||||
asan_write_sized_aligned(addr, access_size);
|
||||
} else {
|
||||
int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
|
||||
const char *str =
|
||||
"is located.%d *byte.*to the right";
|
||||
char expected_str[100];
|
||||
sprintf(expected_str, str, outside_bytes);
|
||||
EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
|
||||
expected_str);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ASAN_ALLOCATOR_VERSION == 2 // Broken with the asan_allocator1
|
||||
TEST(AddressSanitizer, LargeOOBRightTest) {
|
||||
size_t large_power_of_two = 1 << 19;
|
||||
for (size_t i = 16; i <= 256; i *= 2) {
|
||||
size_t size = large_power_of_two - i;
|
||||
char *p = Ident(new char[size]);
|
||||
EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
|
||||
delete [] p;
|
||||
}
|
||||
}
|
||||
#endif // ASAN_ALLOCATOR_VERSION == 2
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
|
||||
oob_test<U1>(10, -1);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
|
||||
oob_test<U1>(kLargeMalloc, -1);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
|
||||
oob_test<U1>(10, 10);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
|
||||
oob_test<U1>(kLargeMalloc, kLargeMalloc);
|
||||
}
|
570
gcc/testsuite/g++.dg/asan/asan_str_test.cc
Normal file
570
gcc/testsuite/g++.dg/asan/asan_str_test.cc
Normal file
@ -0,0 +1,570 @@
|
||||
//=-- asan_str_test.cc ----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
// Used for string functions tests
|
||||
static char global_string[] = "global";
|
||||
static size_t global_string_length = 6;
|
||||
|
||||
// Input to a test is a zero-terminated string str with given length
|
||||
// Accesses to the bytes to the left and to the right of str
|
||||
// are presumed to produce OOB errors
|
||||
void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
|
||||
// Normal strlen calls
|
||||
EXPECT_EQ(strlen(str), length);
|
||||
if (length > 0) {
|
||||
EXPECT_EQ(length - 1, strlen(str + 1));
|
||||
EXPECT_EQ(0U, strlen(str + length));
|
||||
}
|
||||
// Arg of strlen is not malloced, OOB access
|
||||
if (!is_global) {
|
||||
// We don't insert RedZones to the left of global variables
|
||||
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5));
|
||||
}
|
||||
EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBReadMessage(0));
|
||||
// Overwrite terminator
|
||||
str[length] = 'a';
|
||||
// String is not zero-terminated, strlen will lead to OOB access
|
||||
EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0));
|
||||
// Restore terminator
|
||||
str[length] = 0;
|
||||
}
|
||||
TEST(AddressSanitizer, StrLenOOBTest) {
|
||||
// Check heap-allocated string
|
||||
size_t length = Ident(10);
|
||||
char *heap_string = Ident((char*)malloc(length + 1));
|
||||
char stack_string[10 + 1];
|
||||
break_optimization(&stack_string);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
heap_string[i] = 'a';
|
||||
stack_string[i] = 'b';
|
||||
}
|
||||
heap_string[length] = 0;
|
||||
stack_string[length] = 0;
|
||||
StrLenOOBTestTemplate(heap_string, length, false);
|
||||
// TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
|
||||
// make test for stack_string work. Or move it to output tests.
|
||||
// StrLenOOBTestTemplate(stack_string, length, false);
|
||||
StrLenOOBTestTemplate(global_string, global_string_length, true);
|
||||
free(heap_string);
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
TEST(AddressSanitizer, StrNLenOOBTest) {
|
||||
size_t size = Ident(123);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
// Normal strnlen calls.
|
||||
Ident(strnlen(str - 1, 0));
|
||||
Ident(strnlen(str, size));
|
||||
Ident(strnlen(str + size - 1, 1));
|
||||
str[size - 1] = '\0';
|
||||
Ident(strnlen(str, 2 * size));
|
||||
// Argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
|
||||
// Overwrite the terminating '\0' and hit unallocated memory.
|
||||
str[size - 1] = 'z';
|
||||
EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizer, StrDupOOBTest) {
|
||||
size_t size = Ident(42);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
char *new_str;
|
||||
// Normal strdup calls.
|
||||
str[size - 1] = '\0';
|
||||
new_str = strdup(str);
|
||||
free(new_str);
|
||||
new_str = strdup(str + size - 1);
|
||||
free(new_str);
|
||||
// Argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
|
||||
// Overwrite the terminating '\0' and hit unallocated memory.
|
||||
str[size - 1] = 'z';
|
||||
EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCpyOOBTest) {
|
||||
size_t to_size = Ident(30);
|
||||
size_t from_size = Ident(6); // less than to_size
|
||||
char *to = Ident((char*)malloc(to_size));
|
||||
char *from = Ident((char*)malloc(from_size));
|
||||
// Normal strcpy calls.
|
||||
strcpy(from, "hello");
|
||||
strcpy(to, from);
|
||||
strcpy(to + to_size - from_size, from);
|
||||
// Length of "from" is too small.
|
||||
EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
|
||||
// "to" or "from" points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
|
||||
// Overwrite the terminating '\0' character and hit unallocated memory.
|
||||
from[from_size - 1] = '!';
|
||||
EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCpyOOBTest) {
|
||||
size_t to_size = Ident(20);
|
||||
size_t from_size = Ident(6); // less than to_size
|
||||
char *to = Ident((char*)malloc(to_size));
|
||||
// From is a zero-terminated string "hello\0" of length 6
|
||||
char *from = Ident((char*)malloc(from_size));
|
||||
strcpy(from, "hello");
|
||||
// copy 0 bytes
|
||||
strncpy(to, from, 0);
|
||||
strncpy(to - 1, from - 1, 0);
|
||||
// normal strncpy calls
|
||||
strncpy(to, from, from_size);
|
||||
strncpy(to, from, to_size);
|
||||
strncpy(to, from + from_size - 1, to_size);
|
||||
strncpy(to + to_size - 1, from, 1);
|
||||
// One of {to, from} points to not allocated memory
|
||||
EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
|
||||
LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
|
||||
LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
|
||||
RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
|
||||
RightOOBWriteMessage(0));
|
||||
// Length of "to" is too small
|
||||
EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
|
||||
RightOOBWriteMessage(0));
|
||||
// Overwrite terminator in from
|
||||
from[from_size - 1] = '!';
|
||||
// normal strncpy call
|
||||
strncpy(to, from, from_size);
|
||||
// Length of "from" is too small
|
||||
EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
|
||||
RightOOBReadMessage(0));
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
// Users may have different definitions of "strchr" and "index", so provide
|
||||
// function pointer typedefs and overload RunStrChrTest implementation.
|
||||
// We can't use macro for RunStrChrTest body here, as this macro would
|
||||
// confuse EXPECT_DEATH gtest macro.
|
||||
typedef char*(*PointerToStrChr1)(const char*, int);
|
||||
typedef char*(*PointerToStrChr2)(char*, int);
|
||||
|
||||
USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
|
||||
size_t size = Ident(100);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
str[10] = 'q';
|
||||
str[11] = '\0';
|
||||
EXPECT_EQ(str, StrChr(str, 'z'));
|
||||
EXPECT_EQ(str + 10, StrChr(str, 'q'));
|
||||
EXPECT_EQ(NULL, StrChr(str, 'a'));
|
||||
// StrChr argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
|
||||
// Overwrite the terminator and hit not allocated memory.
|
||||
str[11] = 'z';
|
||||
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
|
||||
size_t size = Ident(100);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
str[10] = 'q';
|
||||
str[11] = '\0';
|
||||
EXPECT_EQ(str, StrChr(str, 'z'));
|
||||
EXPECT_EQ(str + 10, StrChr(str, 'q'));
|
||||
EXPECT_EQ(NULL, StrChr(str, 'a'));
|
||||
// StrChr argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
|
||||
// Overwrite the terminator and hit not allocated memory.
|
||||
str[11] = 'z';
|
||||
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
|
||||
RunStrChrTest(&strchr);
|
||||
RunStrChrTest(&index);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
|
||||
// strcmp
|
||||
EXPECT_EQ(0, strcmp("", ""));
|
||||
EXPECT_EQ(0, strcmp("abcd", "abcd"));
|
||||
EXPECT_GT(0, strcmp("ab", "ac"));
|
||||
EXPECT_GT(0, strcmp("abc", "abcd"));
|
||||
EXPECT_LT(0, strcmp("acc", "abc"));
|
||||
EXPECT_LT(0, strcmp("abcd", "abc"));
|
||||
|
||||
// strncmp
|
||||
EXPECT_EQ(0, strncmp("a", "b", 0));
|
||||
EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
|
||||
EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
|
||||
EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
|
||||
EXPECT_GT(0, strncmp("a", "b", 5));
|
||||
EXPECT_GT(0, strncmp("bc", "bcde", 4));
|
||||
EXPECT_LT(0, strncmp("xyz", "xyy", 10));
|
||||
EXPECT_LT(0, strncmp("baa", "aaa", 1));
|
||||
EXPECT_LT(0, strncmp("zyx", "", 2));
|
||||
|
||||
// strcasecmp
|
||||
EXPECT_EQ(0, strcasecmp("", ""));
|
||||
EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
|
||||
EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
|
||||
EXPECT_GT(0, strcasecmp("aB", "Ac"));
|
||||
EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
|
||||
EXPECT_LT(0, strcasecmp("acc", "abc"));
|
||||
EXPECT_LT(0, strcasecmp("ABCd", "abc"));
|
||||
|
||||
// strncasecmp
|
||||
EXPECT_EQ(0, strncasecmp("a", "b", 0));
|
||||
EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
|
||||
EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
|
||||
EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
|
||||
EXPECT_GT(0, strncasecmp("a", "B", 5));
|
||||
EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
|
||||
EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
|
||||
EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
|
||||
EXPECT_LT(0, strncasecmp("zyx", "", 2));
|
||||
|
||||
// memcmp
|
||||
EXPECT_EQ(0, memcmp("a", "b", 0));
|
||||
EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
|
||||
EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
|
||||
EXPECT_GT(0, memcmp("abb\0", "abba", 4));
|
||||
EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
|
||||
EXPECT_LT(0, memcmp("zza", "zyx", 3));
|
||||
}
|
||||
|
||||
typedef int(*PointerToStrCmp)(const char*, const char*);
|
||||
void RunStrCmpTest(PointerToStrCmp StrCmp) {
|
||||
size_t size = Ident(100);
|
||||
int fill = 'o';
|
||||
char *s1 = MallocAndMemsetString(size, fill);
|
||||
char *s2 = MallocAndMemsetString(size, fill);
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
// Normal StrCmp calls
|
||||
Ident(StrCmp(s1, s2));
|
||||
Ident(StrCmp(s1, s2 + size - 1));
|
||||
Ident(StrCmp(s1 + size - 1, s2 + size - 1));
|
||||
s1[size - 1] = 'z';
|
||||
s2[size - 1] = 'x';
|
||||
Ident(StrCmp(s1, s2));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
s1[size - 1] = fill;
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCmpOOBTest) {
|
||||
RunStrCmpTest(&strcmp);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCaseCmpOOBTest) {
|
||||
RunStrCmpTest(&strcasecmp);
|
||||
}
|
||||
|
||||
typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
|
||||
void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
|
||||
size_t size = Ident(100);
|
||||
char *s1 = MallocAndMemsetString(size);
|
||||
char *s2 = MallocAndMemsetString(size);
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
// Normal StrNCmp calls
|
||||
Ident(StrNCmp(s1, s2, size + 2));
|
||||
s1[size - 1] = 'z';
|
||||
s2[size - 1] = 'x';
|
||||
Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
|
||||
s2[size - 1] = 'z';
|
||||
Ident(StrNCmp(s1 - 1, s2 - 1, 0));
|
||||
Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCmpOOBTest) {
|
||||
RunStrNCmpTest(&strncmp);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
|
||||
RunStrNCmpTest(&strncasecmp);
|
||||
}
|
||||
TEST(AddressSanitizer, StrCatOOBTest) {
|
||||
// strcat() reads strlen(to) bytes from |to| before concatenating.
|
||||
size_t to_size = Ident(100);
|
||||
char *to = MallocAndMemsetString(to_size);
|
||||
to[0] = '\0';
|
||||
size_t from_size = Ident(20);
|
||||
char *from = MallocAndMemsetString(from_size);
|
||||
from[from_size - 1] = '\0';
|
||||
// Normal strcat calls.
|
||||
strcat(to, from);
|
||||
strcat(to, from);
|
||||
strcat(to + from_size, from + from_size - 2);
|
||||
// Passing an invalid pointer is an error even when concatenating an empty
|
||||
// string.
|
||||
EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
|
||||
EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(strcat(to + to_size, from), RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
|
||||
|
||||
// "from" is not zero-terminated.
|
||||
from[from_size - 1] = 'z';
|
||||
EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
|
||||
from[from_size - 1] = '\0';
|
||||
// "to" is not zero-terminated.
|
||||
memset(to, 'z', to_size);
|
||||
EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
|
||||
// "to" is too short to fit "from".
|
||||
to[to_size - from_size + 1] = '\0';
|
||||
EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
|
||||
// length of "to" is just enough.
|
||||
strcat(to, from + 1);
|
||||
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCatOOBTest) {
|
||||
// strncat() reads strlen(to) bytes from |to| before concatenating.
|
||||
size_t to_size = Ident(100);
|
||||
char *to = MallocAndMemsetString(to_size);
|
||||
to[0] = '\0';
|
||||
size_t from_size = Ident(20);
|
||||
char *from = MallocAndMemsetString(from_size);
|
||||
// Normal strncat calls.
|
||||
strncat(to, from, 0);
|
||||
strncat(to, from, from_size);
|
||||
from[from_size - 1] = '\0';
|
||||
strncat(to, from, 2 * from_size);
|
||||
// Catenating empty string with an invalid string is still an error.
|
||||
EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
|
||||
strncat(to, from + from_size - 1, 10);
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
|
||||
EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
|
||||
|
||||
memset(from, 'z', from_size);
|
||||
memset(to, 'z', to_size);
|
||||
to[0] = '\0';
|
||||
// "from" is too short.
|
||||
EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
|
||||
// "to" is not zero-terminated.
|
||||
EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBWriteMessage(0));
|
||||
// "to" is too short to fit "from".
|
||||
to[0] = 'z';
|
||||
to[to_size - from_size + 1] = '\0';
|
||||
EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
|
||||
// "to" is just enough.
|
||||
strncat(to, from, from_size - 2);
|
||||
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
static string OverlapErrorMessage(const string &func) {
|
||||
return func + "-param-overlap";
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrArgsOverlapTest) {
|
||||
size_t size = Ident(100);
|
||||
char *str = Ident((char*)malloc(size));
|
||||
|
||||
// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
|
||||
// memmove().
|
||||
#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
|
||||
(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
|
||||
// Check "memcpy". Use Ident() to avoid inlining.
|
||||
memset(str, 'z', size);
|
||||
Ident(memcpy)(str + 1, str + 11, 10);
|
||||
Ident(memcpy)(str, str, 0);
|
||||
EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
|
||||
EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
|
||||
#endif
|
||||
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
// EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
|
||||
// OverlapErrorMessage("memcpy"));
|
||||
|
||||
// Check "strcpy".
|
||||
memset(str, 'z', size);
|
||||
str[9] = '\0';
|
||||
strcpy(str + 10, str);
|
||||
EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
|
||||
EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
|
||||
strcpy(str, str + 5);
|
||||
|
||||
// Check "strncpy".
|
||||
memset(str, 'z', size);
|
||||
strncpy(str, str + 10, 10);
|
||||
EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
|
||||
EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
|
||||
str[10] = '\0';
|
||||
strncpy(str + 11, str, 20);
|
||||
EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
|
||||
|
||||
// Check "strcat".
|
||||
memset(str, 'z', size);
|
||||
str[10] = '\0';
|
||||
str[20] = '\0';
|
||||
strcat(str, str + 10);
|
||||
EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
|
||||
str[10] = '\0';
|
||||
strcat(str + 11, str);
|
||||
EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
|
||||
EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
|
||||
EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
|
||||
|
||||
// Check "strncat".
|
||||
memset(str, 'z', size);
|
||||
str[10] = '\0';
|
||||
strncat(str, str + 10, 10); // from is empty
|
||||
EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
|
||||
str[10] = '\0';
|
||||
str[20] = '\0';
|
||||
strncat(str + 5, str, 5);
|
||||
str[10] = '\0';
|
||||
EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
|
||||
EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
void CallAtoi(const char *nptr) {
|
||||
Ident(atoi(nptr));
|
||||
}
|
||||
void CallAtol(const char *nptr) {
|
||||
Ident(atol(nptr));
|
||||
}
|
||||
void CallAtoll(const char *nptr) {
|
||||
Ident(atoll(nptr));
|
||||
}
|
||||
typedef void(*PointerToCallAtoi)(const char*);
|
||||
|
||||
void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
|
||||
char *array = MallocAndMemsetString(10, '1');
|
||||
// Invalid pointer to the string.
|
||||
EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
|
||||
EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
|
||||
// Die if a buffer doesn't have terminating NULL.
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
// Make last symbol a terminating NULL or other non-digit.
|
||||
array[9] = '\0';
|
||||
Atoi(array);
|
||||
array[9] = 'a';
|
||||
Atoi(array);
|
||||
Atoi(array + 9);
|
||||
// Sometimes we need to detect overflow if no digits are found.
|
||||
memset(array, ' ', 10);
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
array[9] = '-';
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
|
||||
array[8] = '-';
|
||||
Atoi(array);
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
|
||||
RunAtoiOOBTest(&CallAtoi);
|
||||
RunAtoiOOBTest(&CallAtol);
|
||||
RunAtoiOOBTest(&CallAtoll);
|
||||
}
|
||||
|
||||
void CallStrtol(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtol(nptr, endptr, base));
|
||||
}
|
||||
void CallStrtoll(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtoll(nptr, endptr, base));
|
||||
}
|
||||
typedef void(*PointerToCallStrtol)(const char*, char**, int);
|
||||
|
||||
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
|
||||
char *array = MallocAndMemsetString(3);
|
||||
char *endptr = NULL;
|
||||
array[0] = '1';
|
||||
array[1] = '2';
|
||||
array[2] = '3';
|
||||
// Invalid pointer to the string.
|
||||
EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
|
||||
// Buffer overflow if there is no terminating null (depends on base).
|
||||
Strtol(array, &endptr, 3);
|
||||
EXPECT_EQ(array + 2, endptr);
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = 'z';
|
||||
Strtol(array, &endptr, 35);
|
||||
EXPECT_EQ(array + 2, endptr);
|
||||
EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
|
||||
// Add terminating zero to get rid of overflow.
|
||||
array[2] = '\0';
|
||||
Strtol(array, NULL, 36);
|
||||
// Don't check for overflow if base is invalid.
|
||||
Strtol(array - 1, NULL, -1);
|
||||
Strtol(array + 3, NULL, 1);
|
||||
// Sometimes we need to detect overflow if no digits are found.
|
||||
array[0] = array[1] = array[2] = ' ';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = '+';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = '-';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[1] = '+';
|
||||
Strtol(array, NULL, 0);
|
||||
array[1] = array[2] = 'z';
|
||||
Strtol(array, &endptr, 0);
|
||||
EXPECT_EQ(array, endptr);
|
||||
Strtol(array + 2, NULL, 0);
|
||||
EXPECT_EQ(array, endptr);
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrtollOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtoll);
|
||||
}
|
||||
TEST(AddressSanitizer, StrtolOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtol);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && sse2_runtime } } }
|
||||
// { dg-skip-if "" { *-*-* } { "*" } { "-O2" } }
|
||||
// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
|
||||
// { dg-additional-sources "asan_globals_test.cc" }
|
||||
// { dg-additional-sources "asan_globals_test-wrapper.cc" }
|
||||
// { dg-options "-fsanitize=address -fno-builtin -Wall -Wno-format -Werror -g -DASAN_UAR=0 -DASAN_HAS_EXCEPTIONS=1 -DASAN_HAS_BLACKLIST=0 -DASAN_USE_DEJAGNU_GTEST=1 -lasan -lpthread -ldl" }
|
||||
// { dg-additional-options "-DASAN_NEEDS_SEGV=1" { target { ! arm*-*-* } } }
|
||||
// { dg-additional-options "-DASAN_LOW_MEMORY=1 -DASAN_NEEDS_SEGV=0" { target arm*-*-* } }
|
||||
@ -11,3 +11,6 @@
|
||||
// { dg-final { asan-gtest } }
|
||||
|
||||
#include "asan_test.cc"
|
||||
#include "asan_mem_test.cc"
|
||||
#include "asan_str_test.cc"
|
||||
#include "asan_oob_test.cc"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,56 +18,92 @@
|
||||
# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
# define NOINLINE __declspec(noinline)
|
||||
# define USED
|
||||
#else // defined(_WIN32)
|
||||
# define NOINLINE __attribute__((noinline))
|
||||
# define USED __attribute__((used))
|
||||
#endif // defined(_WIN32)
|
||||
#include "sanitizer_test_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#if !defined(__has_feature)
|
||||
#define __has_feature(x) 0
|
||||
#ifdef __linux__
|
||||
# include <sys/prctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
|
||||
__attribute__((no_address_safety_analysis))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
# define SANITIZER_WORDSIZE 64
|
||||
#else
|
||||
# define SANITIZER_WORDSIZE 32
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
// Make the compiler thinks that something is going on there.
|
||||
inline void break_optimization(void *arg) {
|
||||
__asm__ __volatile__("" : : "r" (arg) : "memory");
|
||||
}
|
||||
|
||||
// This function returns its parameter but in such a way that compiler
|
||||
// can not prove it.
|
||||
template<class T>
|
||||
NOINLINE
|
||||
static T Ident(T t) {
|
||||
T ret = t;
|
||||
break_optimization(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Check that pthread_create/pthread_join return success.
|
||||
#define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
|
||||
#define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
|
||||
|
||||
#if ASAN_HAS_EXCEPTIONS
|
||||
# define ASAN_THROW(x) throw (x)
|
||||
#else
|
||||
# define ASAN_THROW(x)
|
||||
#endif
|
||||
|
||||
typedef uint8_t U1;
|
||||
typedef uint16_t U2;
|
||||
typedef uint32_t U4;
|
||||
typedef uint64_t U8;
|
||||
|
||||
static const int kPageSize = 4096;
|
||||
|
||||
const size_t kLargeMalloc = 1 << 24;
|
||||
|
||||
extern void free_aaa(void *p);
|
||||
extern void *malloc_aaa(size_t size);
|
||||
|
||||
template<typename T>
|
||||
NOINLINE void asan_write(T *a) {
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
string RightOOBErrorMessage(int oob_distance, bool is_write);
|
||||
string RightOOBWriteMessage(int oob_distance);
|
||||
string RightOOBReadMessage(int oob_distance);
|
||||
string LeftOOBErrorMessage(int oob_distance, bool is_write);
|
||||
string LeftOOBWriteMessage(int oob_distance);
|
||||
string LeftOOBReadMessage(int oob_distance);
|
||||
string LeftOOBAccessMessage(int oob_distance);
|
||||
char* MallocAndMemsetString(size_t size, char ch);
|
||||
char* MallocAndMemsetString(size_t size);
|
||||
|
||||
extern char glob1[1];
|
||||
extern char glob2[2];
|
||||
extern char glob3[3];
|
||||
extern char glob4[4];
|
||||
extern char glob5[5];
|
||||
extern char glob6[6];
|
||||
extern char glob7[7];
|
||||
extern char glob8[8];
|
||||
extern char glob9[9];
|
||||
extern char glob10[10];
|
||||
extern char glob11[11];
|
||||
extern char glob12[12];
|
||||
extern char glob13[13];
|
||||
extern char glob14[14];
|
||||
extern char glob15[15];
|
||||
extern char glob16[16];
|
||||
extern char glob17[17];
|
||||
extern char glob1000[1000];
|
||||
extern char glob10000[10000];
|
||||
extern char glob100000[100000];
|
||||
extern int GlobalsTest(int x);
|
||||
|
||||
#endif // ASAN_TEST_UTILS_H
|
||||
|
@ -1,3 +1,6 @@
|
||||
#ifndef DEJAGNU_GTEST_H
|
||||
#define DEJAGNU_GTEST_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -113,3 +116,5 @@ main (int argc, const char **argv)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
78
gcc/testsuite/g++.dg/asan/sanitizer_test_utils.h
Normal file
78
gcc/testsuite/g++.dg/asan/sanitizer_test_utils.h
Normal file
@ -0,0 +1,78 @@
|
||||
//===-- sanitizer_test_utils.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of *Sanitizer runtime.
|
||||
// Common unit tests utilities.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_TEST_UTILS_H
|
||||
#define SANITIZER_TEST_UTILS_H
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
# define NOINLINE __declspec(noinline)
|
||||
# define USED
|
||||
#else // defined(_WIN32)
|
||||
# define NOINLINE __attribute__((noinline))
|
||||
# define USED __attribute__((used))
|
||||
#include <stdint.h>
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
#if !defined(__has_feature)
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
|
||||
__attribute__((no_address_safety_analysis))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
|
||||
#endif
|
||||
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
# define SANITIZER_WORDSIZE 64
|
||||
#else
|
||||
# define SANITIZER_WORDSIZE 32
|
||||
#endif
|
||||
|
||||
// Make the compiler thinks that something is going on there.
|
||||
inline void break_optimization(void *arg) {
|
||||
__asm__ __volatile__("" : : "r" (arg) : "memory");
|
||||
}
|
||||
|
||||
// This function returns its parameter but in such a way that compiler
|
||||
// can not prove it.
|
||||
template<class T>
|
||||
NOINLINE
|
||||
static T Ident(T t) {
|
||||
T ret = t;
|
||||
break_optimization(&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Simple stand-alone pseudorandom number generator.
|
||||
// Current algorithm is ANSI C linear congruential PRNG.
|
||||
static inline uint32_t my_rand_r(uint32_t* state) {
|
||||
return (*state = *state * 1103515245 + 12345) >> 16;
|
||||
}
|
||||
|
||||
static uint32_t global_seed = 0;
|
||||
|
||||
static inline uint32_t my_rand() {
|
||||
return my_rand_r(&global_seed);
|
||||
}
|
||||
|
||||
|
||||
#endif // SANITIZER_TEST_UTILS_H
|
Loading…
Reference in New Issue
Block a user