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:
Jakub Jelinek 2013-02-14 09:40:13 +01:00 committed by Jakub Jelinek
parent 8fb067263b
commit 3b0c732405
11 changed files with 1192 additions and 1285 deletions

View File

@ -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

View File

@ -0,0 +1,2 @@
#define DEJAGNU_GTEST_H 1
#include "asan_globals_test.cc"

View File

@ -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) {

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

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

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

View File

@ -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

View File

@ -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

View File

@ -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

View 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