[llvm-commits] [compiler-rt] r173131 - in /compiler-rt/trunk/lib/asan/tests: CMakeLists.txt asan_str_test.cc asan_test.cc
Kostya Serebryany
kcc at google.com
Mon Jan 21 23:01:47 PST 2013
Author: kcc
Date: Tue Jan 22 01:01:47 2013
New Revision: 173131
URL: http://llvm.org/viewvc/llvm-project?rev=173131&view=rev
Log:
[asan] split asan_test.cc even more
Added:
compiler-rt/trunk/lib/asan/tests/asan_str_test.cc
Modified:
compiler-rt/trunk/lib/asan/tests/CMakeLists.txt
compiler-rt/trunk/lib/asan/tests/asan_test.cc
Modified: compiler-rt/trunk/lib/asan/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/CMakeLists.txt?rev=173131&r1=173130&r2=173131&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/asan/tests/CMakeLists.txt Tue Jan 22 01:01:47 2013
@@ -143,6 +143,8 @@
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
asan_compile(ASAN_INST_TEST_OBJECTS asan_mem_test.cc ${arch}
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_str_test.cc ${arch}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
if (APPLE)
asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test.cc ${arch}
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
@@ -180,7 +182,7 @@
# tree with fresh Clang as a host compiler.
set(ASAN_NOINST_TEST_SOURCES asan_noinst_test.cc asan_test_main.cc)
set(ASAN_INST_TEST_SOURCES asan_globals_test.cc asan_test.cc
- asan_oob_test.cc asan_mem_test.cc)
+ asan_oob_test.cc asan_mem_test.cc asan_str_test.cc)
add_library(asan_noinst_test OBJECT ${ASAN_NOINST_TEST_SOURCES})
set_target_compile_flags(asan_noinst_test ${ASAN_UNITTEST_COMMON_CFLAGS})
add_library(asan_inst_test OBJECT
Added: compiler-rt/trunk/lib/asan/tests/asan_str_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_str_test.cc?rev=173131&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_str_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_str_test.cc Tue Jan 22 01:01:47 2013
@@ -0,0 +1,572 @@
+//=-- asan_str_test.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// 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);
+}
+
+
Modified: compiler-rt/trunk/lib/asan/tests/asan_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test.cc?rev=173131&r1=173130&r2=173131&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test.cc (original)
+++ compiler-rt/trunk/lib/asan/tests/asan_test.cc Tue Jan 22 01:01:47 2013
@@ -704,57 +704,6 @@
return string(expected_str);
}
-// Tests for string functions
-
-// 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);
-}
-
char* MallocAndMemsetString(size_t size, char ch) {
char *s = Ident((char*)malloc(size));
memset(s, ch, size);
@@ -765,542 +714,6 @@
return MallocAndMemsetString(size, 'z');
}
-#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);
-}
-
-// At the moment we instrument memcpy/memove/memset calls at compile time so we
-// can't handle OOB error if these functions are called by pointer, see disabled
-// MemIntrinsicCallByPointerTest below
-typedef void*(*PointerToMemTransfer)(void*, const void*, size_t);
-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), RightOOBWriteMessage(0));
- free(array);
-}
-
-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), RightOOBWriteMessage(0));
- free(src);
- free(dst);
-}
-
-TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) {
- CallMemSetByPointer(&memset);
- CallMemTransferByPointer(&memcpy);
- CallMemTransferByPointer(&memmove);
-}
-
#if defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
#define READ_TEST(READ_N_BYTES) \
char *x = new char[10]; \
More information about the llvm-commits
mailing list