2013-01-22 15:01:47 +08:00
|
|
|
//=-- 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"
|
|
|
|
|
2013-09-20 19:03:27 +08:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
|
|
|
|
#endif
|
2013-09-20 18:56:34 +08:00
|
|
|
|
2013-01-22 15:01:47 +08:00
|
|
|
// Used for string functions tests
|
|
|
|
static char global_string[] = "global";
|
|
|
|
static size_t global_string_length = 6;
|
|
|
|
|
2016-02-24 09:28:51 +08:00
|
|
|
const char kStackReadUnderflow[] =
|
|
|
|
#if !GTEST_USES_SIMPLE_RE
|
|
|
|
ASAN_PCRE_DOTALL
|
|
|
|
"READ.*"
|
|
|
|
#endif
|
|
|
|
"underflows this variable";
|
|
|
|
const char kStackReadOverflow[] =
|
|
|
|
#if !GTEST_USES_SIMPLE_RE
|
|
|
|
ASAN_PCRE_DOTALL
|
|
|
|
"READ.*"
|
|
|
|
#endif
|
|
|
|
"overflows this variable";
|
2016-02-24 08:41:29 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
enum class OOBKind {
|
|
|
|
Heap,
|
|
|
|
Stack,
|
|
|
|
Global,
|
|
|
|
};
|
|
|
|
|
|
|
|
string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
|
|
|
return oob_kind == OOBKind::Stack ? kStackReadUnderflow
|
|
|
|
: ::LeftOOBReadMessage(oob_distance);
|
|
|
|
}
|
|
|
|
|
|
|
|
string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
|
|
|
return oob_kind == OOBKind::Stack ? kStackReadOverflow
|
|
|
|
: ::RightOOBReadMessage(oob_distance);
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2013-01-22 15:01:47 +08:00
|
|
|
// 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
|
2016-02-24 08:41:29 +08:00
|
|
|
void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) {
|
2013-01-22 15:01:47 +08:00
|
|
|
// 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
|
2016-02-24 08:41:29 +08:00
|
|
|
if (oob_kind != OOBKind::Global) {
|
2013-01-22 15:01:47 +08:00
|
|
|
// We don't insert RedZones to the left of global variables
|
2016-02-24 08:41:29 +08:00
|
|
|
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1));
|
|
|
|
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5));
|
2013-01-22 15:01:47 +08:00
|
|
|
}
|
2016-02-24 08:41:29 +08:00
|
|
|
EXPECT_DEATH(Ident(strlen(str + length + 1)),
|
|
|
|
RightOOBReadMessage(oob_kind, 0));
|
2013-01-22 15:01:47 +08:00
|
|
|
// Overwrite terminator
|
|
|
|
str[length] = 'a';
|
|
|
|
// String is not zero-terminated, strlen will lead to OOB access
|
2016-02-24 08:41:29 +08:00
|
|
|
EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0));
|
|
|
|
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0));
|
2013-01-22 15:01:47 +08:00
|
|
|
// 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;
|
2016-02-24 08:41:29 +08:00
|
|
|
StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap);
|
|
|
|
StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack);
|
|
|
|
StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global);
|
2013-01-22 15:01:47 +08:00
|
|
|
free(heap_string);
|
|
|
|
}
|
|
|
|
|
2017-10-07 08:04:24 +08:00
|
|
|
// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling
|
|
|
|
// the interceptor.
|
|
|
|
#if !defined(__ANDROID__) || defined(__LP64__)
|
2013-09-05 09:13:49 +08:00
|
|
|
TEST(AddressSanitizer, WcsLenTest) {
|
2013-09-06 19:08:12 +08:00
|
|
|
EXPECT_EQ(0U, wcslen(Ident(L"")));
|
2013-09-05 09:13:49 +08:00
|
|
|
size_t hello_len = 13;
|
|
|
|
size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
|
|
|
|
EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
|
|
|
|
wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
|
|
|
|
memcpy(heap_string, L"Hello, World!", hello_size);
|
|
|
|
EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
|
|
|
|
EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
|
2013-09-08 21:23:29 +08:00
|
|
|
free(heap_string);
|
2013-09-05 09:13:49 +08:00
|
|
|
}
|
2017-10-07 08:04:24 +08:00
|
|
|
#endif
|
2013-09-05 09:13:49 +08:00
|
|
|
|
2014-03-07 17:39:01 +08:00
|
|
|
#if SANITIZER_TEST_HAS_STRNLEN
|
2013-01-22 15:01:47 +08:00
|
|
|
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);
|
|
|
|
}
|
2014-03-07 17:39:01 +08:00
|
|
|
#endif // SANITIZER_TEST_HAS_STRNLEN
|
2013-01-22 15:01:47 +08:00
|
|
|
|
2016-11-02 23:39:08 +08:00
|
|
|
// This test fails with the WinASan dynamic runtime because we fail to intercept
|
|
|
|
// strdup.
|
|
|
|
#if defined(_MSC_VER) && defined(_DLL)
|
|
|
|
#define MAYBE_StrDupOOBTest DISABLED_StrDupOOBTest
|
|
|
|
#else
|
|
|
|
#define MAYBE_StrDupOOBTest StrDupOOBTest
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TEST(AddressSanitizer, MAYBE_StrDupOOBTest) {
|
2013-01-22 15:01:47 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-06-01 17:37:22 +08:00
|
|
|
#if SANITIZER_TEST_HAS_STRNDUP
|
|
|
|
TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) {
|
|
|
|
size_t size = Ident(42);
|
|
|
|
char *str = MallocAndMemsetString(size);
|
|
|
|
char *new_str;
|
|
|
|
// Normal strndup calls.
|
|
|
|
str[size - 1] = '\0';
|
|
|
|
new_str = strndup(str, size - 13);
|
|
|
|
free(new_str);
|
|
|
|
new_str = strndup(str + size - 1, 13);
|
|
|
|
free(new_str);
|
|
|
|
// Argument points to not allocated memory.
|
|
|
|
EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1));
|
|
|
|
EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0));
|
|
|
|
// Overwrite the terminating '\0' and hit unallocated memory.
|
|
|
|
str[size - 1] = 'z';
|
|
|
|
EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0));
|
|
|
|
// Check handling of non 0 terminated strings.
|
|
|
|
Ident(new_str = strndup(str + size - 1, 0));
|
|
|
|
free(new_str);
|
|
|
|
Ident(new_str = strndup(str + size - 1, 1));
|
|
|
|
free(new_str);
|
|
|
|
EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0));
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
#endif // SANITIZER_TEST_HAS_STRNDUP
|
|
|
|
|
2013-01-22 15:01:47 +08:00
|
|
|
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);
|
|
|
|
|
2016-02-11 04:02:04 +08:00
|
|
|
template<typename StrChrFn>
|
|
|
|
static void RunStrChrTestImpl(StrChrFn *StrChr) {
|
2013-01-22 15:01:47 +08:00
|
|
|
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);
|
|
|
|
}
|
2016-02-11 04:02:04 +08:00
|
|
|
|
|
|
|
// Prefer to use the standard signature if both are available.
|
|
|
|
UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) {
|
|
|
|
RunStrChrTestImpl(StrChr);
|
|
|
|
}
|
|
|
|
UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) {
|
|
|
|
RunStrChrTestImpl(StrChr);
|
2013-01-22 15:01:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
|
2016-02-11 04:02:04 +08:00
|
|
|
RunStrChrTest(&strchr, 0);
|
2014-09-23 23:42:04 +08:00
|
|
|
// No index() on Windows and on Android L.
|
|
|
|
#if !defined(_WIN32) && !defined(__ANDROID__)
|
2016-02-11 04:02:04 +08:00
|
|
|
RunStrChrTest(&index, 0);
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|
2013-01-22 15:01:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2014-05-08 23:05:42 +08:00
|
|
|
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
2013-01-22 15:01:47 +08:00
|
|
|
// 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));
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|
2013-01-22 15:01:47 +08:00
|
|
|
|
|
|
|
// 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));
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2014-05-08 23:05:42 +08:00
|
|
|
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
2013-01-22 15:01:47 +08:00
|
|
|
TEST(AddressSanitizer, StrCaseCmpOOBTest) {
|
|
|
|
RunStrCmpTest(&strcasecmp);
|
|
|
|
}
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|
2013-01-22 15:01:47 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-05-08 23:05:42 +08:00
|
|
|
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
2013-01-22 15:01:47 +08:00
|
|
|
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
|
|
|
|
RunStrNCmpTest(&strncasecmp);
|
|
|
|
}
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|
|
|
|
|
2013-01-22 15:01:47 +08:00
|
|
|
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, 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 too short to fit "from".
|
2015-04-07 02:00:26 +08:00
|
|
|
memset(to, 'z', to_size);
|
2013-01-22 15:01:47 +08:00
|
|
|
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, 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 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.
|
[compiler-rt] Fix warnings in interception code
Summary:
This patch is re-introducing the code to fix the
dynamic hooking on windows and to fix a compiler
warning on Apple.
Related patches:
* https://reviews.llvm.org/D22641
* https://reviews.llvm.org/D22610
* https://reviews.llvm.org/rL276311
* https://reviews.llvm.org/rL276490
Both architecture are using different techniques to
hook on library functions (memchr, strcpy,...).
On Apple, the function is not dynamically hooked and
the symbol always points to a valid function
(i.e. can't be null). The REAL macro returns the
symbol.
On windows, the function is dynamically patch and the
REAL(...) function may or may not be null. It depend
on whether or not the function was hooked correctly.
Also, on windows memcpy and memmove are the same.
```
#if !defined(__APPLE__)
[...]
# define REAL(x) __interception::PTR_TO_REAL(x)
# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src)
[...]
#else // __APPLE__
[...]
# define REAL(x) x
# define ASSIGN_REAL(x, y)
[...]
#endif // __APPLE__
Reviewers: rnk
Subscribers: kcc, hans, kubabrecka, llvm-commits, bruno, chrisha
Differential Revision: https://reviews.llvm.org/D22758
llvm-svn: 276885
2016-07-28 00:16:54 +08:00
|
|
|
#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
|
2013-01-22 15:01:47 +08:00
|
|
|
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"));
|
[compiler-rt] Fix warnings in interception code
Summary:
This patch is re-introducing the code to fix the
dynamic hooking on windows and to fix a compiler
warning on Apple.
Related patches:
* https://reviews.llvm.org/D22641
* https://reviews.llvm.org/D22610
* https://reviews.llvm.org/rL276311
* https://reviews.llvm.org/rL276490
Both architecture are using different techniques to
hook on library functions (memchr, strcpy,...).
On Apple, the function is not dynamically hooked and
the symbol always points to a valid function
(i.e. can't be null). The REAL macro returns the
symbol.
On windows, the function is dynamically patch and the
REAL(...) function may or may not be null. It depend
on whether or not the function was hooked correctly.
Also, on windows memcpy and memmove are the same.
```
#if !defined(__APPLE__)
[...]
# define REAL(x) __interception::PTR_TO_REAL(x)
# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src)
[...]
#else // __APPLE__
[...]
# define REAL(x) x
# define ASSIGN_REAL(x, y)
[...]
#endif // __APPLE__
Reviewers: rnk
Subscribers: kcc, hans, kubabrecka, llvm-commits, bruno, chrisha
Differential Revision: https://reviews.llvm.org/D22758
llvm-svn: 276885
2016-07-28 00:16:54 +08:00
|
|
|
#endif
|
2013-01-22 15:01:47 +08:00
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
2015-04-07 02:00:26 +08:00
|
|
|
// Make last symbol a terminating NULL
|
2013-01-22 15:01:47 +08:00
|
|
|
array[9] = '\0';
|
|
|
|
Atoi(array);
|
|
|
|
// 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));
|
|
|
|
free(array);
|
|
|
|
}
|
|
|
|
|
2014-05-08 23:05:42 +08:00
|
|
|
#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
|
2014-09-15 19:34:12 +08:00
|
|
|
void CallAtoi(const char *nptr) {
|
|
|
|
Ident(atoi(nptr));
|
|
|
|
}
|
|
|
|
void CallAtol(const char *nptr) {
|
|
|
|
Ident(atol(nptr));
|
|
|
|
}
|
|
|
|
void CallAtoll(const char *nptr) {
|
|
|
|
Ident(atoll(nptr));
|
|
|
|
}
|
2013-01-22 15:01:47 +08:00
|
|
|
TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
|
|
|
|
RunAtoiOOBTest(&CallAtoi);
|
|
|
|
RunAtoiOOBTest(&CallAtol);
|
|
|
|
RunAtoiOOBTest(&CallAtoll);
|
|
|
|
}
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|
2013-01-22 15:01:47 +08:00
|
|
|
|
|
|
|
typedef void(*PointerToCallStrtol)(const char*, char**, int);
|
|
|
|
|
|
|
|
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
|
|
|
|
char *array = MallocAndMemsetString(3);
|
|
|
|
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).
|
|
|
|
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
|
|
|
array[2] = 'z';
|
|
|
|
EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
|
|
|
|
// Add terminating zero to get rid of overflow.
|
|
|
|
array[2] = '\0';
|
|
|
|
Strtol(array, NULL, 36);
|
|
|
|
// 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));
|
|
|
|
free(array);
|
|
|
|
}
|
|
|
|
|
2014-05-08 23:05:42 +08:00
|
|
|
#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
|
2014-09-15 19:34:12 +08:00
|
|
|
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));
|
|
|
|
}
|
2013-01-22 15:01:47 +08:00
|
|
|
TEST(AddressSanitizer, StrtollOOBTest) {
|
|
|
|
RunStrtolOOBTest(&CallStrtoll);
|
|
|
|
}
|
|
|
|
TEST(AddressSanitizer, StrtolOOBTest) {
|
|
|
|
RunStrtolOOBTest(&CallStrtol);
|
|
|
|
}
|
2014-05-08 23:05:42 +08:00
|
|
|
#endif
|