diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/asan/asan_test.cc | 490 |
2 files changed, 356 insertions, 138 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0df71a5..3943c2f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2013-01-10 Kostya Serebryany <kcc@google.com> + + * g++.dg/asan/asan_test.cc: Sync from upstream. + 2013-01-10 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/55921 diff --git a/gcc/testsuite/g++.dg/asan/asan_test.cc b/gcc/testsuite/g++.dg/asan/asan_test.cc index 32c2ad2..9cfa9e0 100644 --- a/gcc/testsuite/g++.dg/asan/asan_test.cc +++ b/gcc/testsuite/g++.dg/asan/asan_test.cc @@ -17,6 +17,15 @@ #include <stdint.h> #include <setjmp.h> #include <assert.h> +#include <algorithm> + +#ifdef __linux__ +# include <sys/prctl.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <fcntl.h> +#include <unistd.h> +#endif #if defined(__i386__) || defined(__x86_64__) #include <emmintrin.h> @@ -242,7 +251,7 @@ void OOBTest() { 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 + 3 * sizeof(T)); 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; @@ -298,6 +307,18 @@ TEST(AddressSanitizer, OOBRightTest) { } } +#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, UAF_char) { const char *uaf_string = "AddressSanitizer:.*heap-use-after-free"; EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string); @@ -456,6 +477,24 @@ TEST(AddressSanitizer, HugeMallocTest) { } #endif +#ifndef __APPLE__ +void MemalignRun(size_t align, size_t size, int idx) { + char *p = (char *)memalign(align, size); + Ident(p)[idx] = 0; + free(p); +} + +TEST(AddressSanitizer, memalign) { + for (int align = 16; align <= (1 << 23); align *= 2) { + size_t size = align * 5; + EXPECT_DEATH(MemalignRun(align, size, -1), + "is located 1 bytes to the left"); + EXPECT_DEATH(MemalignRun(align, size, size + 1), + "is located 1 bytes to the right"); + } +} +#endif + TEST(AddressSanitizer, ThreadedMallocStressTest) { const int kNumThreads = 4; const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000; @@ -784,14 +823,39 @@ TEST(AddressSanitizer, Store128Test) { } #endif -static string RightOOBErrorMessage(int oob_distance) { +static string RightOOBErrorMessage(int oob_distance, bool is_write) { assert(oob_distance >= 0); char expected_str[100]; - sprintf(expected_str, "located %d bytes to the right", oob_distance); + sprintf(expected_str, ASAN_PCRE_DOTALL "%s.*located %d bytes to the right", + is_write ? "WRITE" : "READ", oob_distance); return string(expected_str); } -static string LeftOOBErrorMessage(int oob_distance) { +static string RightOOBWriteMessage(int oob_distance) { + return RightOOBErrorMessage(oob_distance, /*is_write*/true); +} + +static string RightOOBReadMessage(int oob_distance) { + return RightOOBErrorMessage(oob_distance, /*is_write*/false); +} + +static string LeftOOBErrorMessage(int oob_distance, bool is_write) { + assert(oob_distance > 0); + char expected_str[100]; + sprintf(expected_str, ASAN_PCRE_DOTALL "%s.*located %d bytes to the left", + is_write ? "WRITE" : "READ", oob_distance); + return string(expected_str); +} + +static string LeftOOBWriteMessage(int oob_distance) { + return LeftOOBErrorMessage(oob_distance, /*is_write*/true); +} + +static string LeftOOBReadMessage(int oob_distance) { + return LeftOOBErrorMessage(oob_distance, /*is_write*/false); +} + +static string LeftOOBAccessMessage(int oob_distance) { assert(oob_distance > 0); char expected_str[100]; sprintf(expected_str, "located %d bytes to the left", oob_distance); @@ -805,44 +869,48 @@ void MemSetOOBTestTemplate(size_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(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); + 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), - RightOOBErrorMessage(0)); - EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6), - RightOOBErrorMessage(4)); - EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)), - RightOOBErrorMessage(2 * sizeof(T) - 1)); + 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), - RightOOBErrorMessage(sizeof(T))); + 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), - LeftOOBErrorMessage(1)); - EXPECT_DEATH(memset((char*)array - 5, 0, 6), - LeftOOBErrorMessage(5)); - EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)), - LeftOOBErrorMessage(5 * sizeof(T))); + 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)), - LeftOOBErrorMessage(2 * sizeof(T))); + 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), - LeftOOBErrorMessage(2)); + EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4), + LeftOOBWriteMessage(2)); free(array); } @@ -854,6 +922,51 @@ TEST(AddressSanitizer, MemSetOOBTest) { // 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) { @@ -877,27 +990,27 @@ void MemTransferOOBTestTemplate(size_t length) { // try to change mem to the right of dest EXPECT_DEATH(M::transfer(dest + 1, src, size), - RightOOBErrorMessage(sizeof(T) - 1)); + RightOOBWriteMessage(0)); EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5), - RightOOBErrorMessage(3)); + RightOOBWriteMessage(0)); // try to change mem to the left of dest EXPECT_DEATH(M::transfer(dest - 2, src, size), - LeftOOBErrorMessage(2 * sizeof(T))); + LeftOOBWriteMessage(2 * sizeof(T))); EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4), - LeftOOBErrorMessage(3)); + LeftOOBWriteMessage(3)); // try to access mem to the right of src EXPECT_DEATH(M::transfer(dest, src + 2, size), - RightOOBErrorMessage(2 * sizeof(T) - 1)); + RightOOBReadMessage(0)); EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6), - RightOOBErrorMessage(2)); + RightOOBReadMessage(0)); // try to access mem to the left of src EXPECT_DEATH(M::transfer(dest, src - 1, size), - LeftOOBErrorMessage(sizeof(T))); + LeftOOBReadMessage(sizeof(T))); EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7), - LeftOOBErrorMessage(6)); + LeftOOBReadMessage(6)); // Generally we don't need to test cases where both accessing src and writing // to dest address to poisoned memory. @@ -906,10 +1019,10 @@ void MemTransferOOBTestTemplate(size_t length) { 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), - LeftOOBErrorMessage(sizeof(T))); + LeftOOBWriteMessage(sizeof(T))); // try to access mem to both sides of src EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2), - LeftOOBErrorMessage(2 * sizeof(T))); + LeftOOBReadMessage(2 * sizeof(T))); free(src); free(dest); @@ -920,7 +1033,7 @@ void MemTransferOOBTestTemplate(size_t length) { class MemCpyWrapper { public: static void* transfer(void *to, const void *from, size_t size) { - return memcpy(to, from, size); + return Ident(memcpy)(to, from, size); } }; TEST(AddressSanitizer, MemCpyOOBTest) { @@ -931,7 +1044,7 @@ TEST(AddressSanitizer, MemCpyOOBTest) { class MemMoveWrapper { public: static void* transfer(void *to, const void *from, size_t size) { - return memmove(to, from, size); + return Ident(memmove)(to, from, size); } }; TEST(AddressSanitizer, MemMoveOOBTest) { @@ -958,15 +1071,15 @@ void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) { // 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)), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5)); + EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5)); } - EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0)); + 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)), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0)); // Restore terminator str[length] = 0; } @@ -1010,11 +1123,11 @@ TEST(AddressSanitizer, StrNLenOOBTest) { str[size - 1] = '\0'; Ident(strnlen(str, 2 * size)); // Argument points to not allocated memory. - EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0)); + 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)), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0)); free(str); } #endif @@ -1030,11 +1143,11 @@ TEST(AddressSanitizer, StrDupOOBTest) { new_str = strdup(str + size - 1); free(new_str); // Argument points to not allocated memory. - EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0)); + 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)), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0)); free(str); } @@ -1048,15 +1161,15 @@ TEST(AddressSanitizer, StrCpyOOBTest) { strcpy(to, from); strcpy(to + to_size - from_size, from); // Length of "from" is too small. - EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0)); // "to" or "from" points to not allocated memory. - EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBErrorMessage(0)); + 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)), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0)); free(to); free(from); } @@ -1078,25 +1191,25 @@ TEST(AddressSanitizer, StrNCpyOOBTest) { 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)), - LeftOOBErrorMessage(1)); + LeftOOBReadMessage(1)); EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)), - LeftOOBErrorMessage(1)); + LeftOOBWriteMessage(1)); EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)), - RightOOBErrorMessage(0)); + RightOOBReadMessage(0)); EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)), - RightOOBErrorMessage(0)); + RightOOBWriteMessage(0)); // Length of "to" is too small EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)), - RightOOBErrorMessage(0)); + RightOOBWriteMessage(0)); EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)), - RightOOBErrorMessage(0)); + 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)), - RightOOBErrorMessage(0)); + RightOOBReadMessage(0)); free(to); free(from); } @@ -1117,11 +1230,11 @@ USED static void RunStrChrTest(PointerToStrChr1 StrChr) { 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')), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0)); + 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')), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0)); free(str); } USED static void RunStrChrTest(PointerToStrChr2 StrChr) { @@ -1133,11 +1246,11 @@ USED static void RunStrChrTest(PointerToStrChr2 StrChr) { 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')), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0)); + 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')), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0)); free(str); } @@ -1198,8 +1311,9 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) { typedef int(*PointerToStrCmp)(const char*, const char*); void RunStrCmpTest(PointerToStrCmp StrCmp) { size_t size = Ident(100); - char *s1 = MallocAndMemsetString(size); - char *s2 = MallocAndMemsetString(size); + int fill = 'o'; + char *s1 = MallocAndMemsetString(size, fill); + char *s2 = MallocAndMemsetString(size, fill); s1[size - 1] = '\0'; s2[size - 1] = '\0'; // Normal StrCmp calls @@ -1210,14 +1324,14 @@ void RunStrCmpTest(PointerToStrCmp StrCmp) { s2[size - 1] = 'x'; Ident(StrCmp(s1, s2)); // One of arguments points to not allocated memory. - EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBErrorMessage(0)); + 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. - s2[size - 1] = 'z'; - EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBErrorMessage(0)); + 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); } @@ -1246,13 +1360,13 @@ void RunStrNCmpTest(PointerToStrNCmp StrNCmp) { 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), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0)); + 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); } @@ -1274,22 +1388,23 @@ TEST(AddressSanitizer, MemCmpOOBTest) { 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), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1)); - EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); - EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0)); free(s1); free(s2); } 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'; @@ -1302,23 +1417,23 @@ TEST(AddressSanitizer, StrCatOOBTest) { 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), LeftOOBErrorMessage(1)); + 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), LeftOOBErrorMessage(1)); - EXPECT_DEATH(strcat(to, from - 1), LeftOOBErrorMessage(1)); - EXPECT_DEATH(strcat(to + to_size, from), RightOOBErrorMessage(0)); - EXPECT_DEATH(strcat(to, from + from_size), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0)); // length of "to" is just enough. strcat(to, from + 1); @@ -1327,6 +1442,7 @@ TEST(AddressSanitizer, StrCatOOBTest) { } 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'; @@ -1338,25 +1454,25 @@ TEST(AddressSanitizer, StrNCatOOBTest) { 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), LeftOOBErrorMessage(1)); + 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), LeftOOBErrorMessage(1)); - EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBErrorMessage(1)); - EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBErrorMessage(0)); - EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0)); // "to" is not zero-terminated. - EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0)); // "to" is just enough. strncat(to, from, from_size - 2); @@ -1447,10 +1563,10 @@ typedef void(*PointerToCallAtoi)(const char*); void RunAtoiOOBTest(PointerToCallAtoi Atoi) { char *array = MallocAndMemsetString(10, '1'); // Invalid pointer to the string. - EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1)); - EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); // Make last symbol a terminating NULL or other non-digit. array[9] = '\0'; Atoi(array); @@ -1459,13 +1575,13 @@ void RunAtoiOOBTest(PointerToCallAtoi Atoi) { Atoi(array + 9); // Sometimes we need to detect overflow if no digits are found. memset(array, ' ', 10); - EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); array[9] = '-'; - EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); - EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0)); + EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); + EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0)); array[8] = '-'; Atoi(array); - delete array; + free(array); } TEST(AddressSanitizer, AtoiAndFriendsOOBTest) { @@ -1489,16 +1605,16 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) { array[1] = '2'; array[2] = '3'; // Invalid pointer to the string. - EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0)); - EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1)); + 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), RightOOBErrorMessage(0)); + 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0)); // Add terminating zero to get rid of overflow. array[2] = '\0'; Strtol(array, NULL, 36); @@ -1507,11 +1623,11 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) { 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); array[2] = '+'; - EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); array[2] = '-'; - EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0)); + EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); array[1] = '+'; Strtol(array, NULL, 0); array[1] = array[2] = 'z'; @@ -1519,7 +1635,7 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) { EXPECT_EQ(array, endptr); Strtol(array + 2, NULL, 0); EXPECT_EQ(array, endptr); - delete array; + free(array); } TEST(AddressSanitizer, StrtollOOBTest) { @@ -1538,7 +1654,7 @@ typedef void*(*PointerToMemSet)(void*, int, size_t); void CallMemSetByPointer(PointerToMemSet MemSet) { size_t size = Ident(100); char *array = Ident((char*)malloc(size)); - EXPECT_DEATH(MemSet(array, 0, 101), RightOOBErrorMessage(0)); + EXPECT_DEATH(MemSet(array, 0, 101), RightOOBWriteMessage(0)); free(array); } @@ -1546,7 +1662,7 @@ void CallMemTransferByPointer(PointerToMemTransfer MemTransfer) { size_t size = Ident(100); char *src = Ident((char*)malloc(size)); char *dst = Ident((char*)malloc(size)); - EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBErrorMessage(0)); + EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBWriteMessage(0)); free(src); free(dst); } @@ -1557,12 +1673,51 @@ TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) { CallMemTransferByPointer(&memmove); } +#if defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__) +TEST(AddressSanitizer, pread) { + char *x = new char[10]; + int fd = open("/proc/self/stat", O_RDONLY); + ASSERT_GT(fd, 0); + EXPECT_DEATH(pread(fd, x, 15, 0), + ASAN_PCRE_DOTALL + "AddressSanitizer: heap-buffer-overflow" + ".* is located 0 bytes to the right of 10-byte region"); + close(fd); + delete [] x; +} + +TEST(AddressSanitizer, pread64) { + char *x = new char[10]; + int fd = open("/proc/self/stat", O_RDONLY); + ASSERT_GT(fd, 0); + EXPECT_DEATH(pread64(fd, x, 15, 0), + ASAN_PCRE_DOTALL + "AddressSanitizer: heap-buffer-overflow" + ".* is located 0 bytes to the right of 10-byte region"); + close(fd); + delete [] x; +} + +TEST(AddressSanitizer, read) { + char *x = new char[10]; + int fd = open("/proc/self/stat", O_RDONLY); + ASSERT_GT(fd, 0); + EXPECT_DEATH(read(fd, x, 15), + ASAN_PCRE_DOTALL + "AddressSanitizer: heap-buffer-overflow" + ".* is located 0 bytes to the right of 10-byte region"); + close(fd); + delete [] x; +} + +#endif // defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__) + // This test case fails // Clang optimizes memcpy/memset calls which lead to unaligned access TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) { int size = Ident(4096); char *s = Ident((char*)malloc(size)); - EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBErrorMessage(0)); + EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0)); free(s); } @@ -1617,19 +1772,30 @@ TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) { "malloc_fff.*malloc_eee.*malloc_ddd"); } +static bool TryToSetThreadName(const char *name) { +#if defined(__linux__) && defined(PR_SET_NAME) + return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); +#else + return false; +#endif +} + void *ThreadedTestAlloc(void *a) { + EXPECT_EQ(true, TryToSetThreadName("AllocThr")); int **p = (int**)a; *p = new int; return 0; } void *ThreadedTestFree(void *a) { + EXPECT_EQ(true, TryToSetThreadName("FreeThr")); int **p = (int**)a; delete *p; return 0; } void *ThreadedTestUse(void *a) { + EXPECT_EQ(true, TryToSetThreadName("UseThr")); int **p = (int**)a; **p = 1; return 0; @@ -1654,6 +1820,30 @@ TEST(AddressSanitizer, ThreadedTest) { ".*Thread T.*created"); } +void *ThreadedTestFunc(void *unused) { + // Check if prctl(PR_SET_NAME) is supported. Return if not. + if (!TryToSetThreadName("TestFunc")) + return 0; + EXPECT_DEATH(ThreadedTestSpawn(), + ASAN_PCRE_DOTALL + "WRITE .*thread T. .UseThr." + ".*freed by thread T. .FreeThr. here:" + ".*previously allocated by thread T. .AllocThr. here:" + ".*Thread T. .UseThr. created by T.*TestFunc" + ".*Thread T. .FreeThr. created by T" + ".*Thread T. .AllocThr. created by T" + ""); + return 0; +} + +TEST(AddressSanitizer, ThreadNamesTest) { + // Run ThreadedTestFunc in a separate thread because it tries to set a + // thread name and we don't want to change the main thread's name. + pthread_t t; + PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0); + PTHREAD_JOIN(t, 0); +} + #if ASAN_NEEDS_SEGV TEST(AddressSanitizer, ShadowGapTest) { #if SANITIZER_WORDSIZE == 32 @@ -1868,6 +2058,27 @@ TEST(AddressSanitizer, AttributeNoAddressSafetyTest) { Ident(NoAddressSafety)(); } +static string MismatchStr(const string &str) { + return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str; +} + +// This test is disabled until we enable alloc_dealloc_mismatch by default. +// The feature is also tested by lit tests. +TEST(AddressSanitizer, DISABLED_AllocDeallocMismatch) { + EXPECT_DEATH(free(Ident(new int)), + MismatchStr("operator new vs free")); + EXPECT_DEATH(free(Ident(new int[2])), + MismatchStr("operator new \\[\\] vs free")); + EXPECT_DEATH(delete (Ident(new int[2])), + MismatchStr("operator new \\[\\] vs operator delete")); + EXPECT_DEATH(delete (Ident((int*)malloc(2 * sizeof(int)))), + MismatchStr("malloc vs operator delete")); + EXPECT_DEATH(delete [] (Ident(new int)), + MismatchStr("operator new vs operator delete \\[\\]")); + EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))), + MismatchStr("malloc vs operator delete \\[\\]")); +} + // ------------------ demo tests; run each one-by-one ------------- // e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests TEST(AddressSanitizer, DISABLED_DemoThreadedTest) { @@ -2033,53 +2244,56 @@ TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) { EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free"); } +// For libdispatch tests below we check that ASan got to the shadow byte +// legend, i.e. managed to print the thread stacks (this almost certainly +// means that the libdispatch task creation has been intercepted correctly). TEST(AddressSanitizerMac, GCDDispatchAsync) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDDispatchSync) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDDispatchAfter) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDSourceEvent) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDSourceCancel) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend"); } TEST(AddressSanitizerMac, GCDGroupAsync) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. - EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte and word"); + EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend"); } void *MallocIntrospectionLockWorker(void *_) { @@ -2172,7 +2386,7 @@ TEST(AddressSanitizerMac, NSURLDeallocation) { TEST(AddressSanitizerMac, Mstats) { malloc_statistics_t stats1, stats2; malloc_zone_statistics(/*all zones*/NULL, &stats1); - const int kMallocSize = 100000; + const size_t kMallocSize = 100000; void *alloc = Ident(malloc(kMallocSize)); malloc_zone_statistics(/*all zones*/NULL, &stats2); EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use); |