diff options
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 38 | ||||
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.h | 3 | ||||
-rw-r--r-- | compiler-rt/lib/asan/asan_stack.cc | 4 | ||||
-rw-r--r-- | compiler-rt/lib/asan/tests/asan_test.cc | 32 |
4 files changed, 65 insertions, 12 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 09c40c1d712..3deeca02a0e 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -28,6 +28,7 @@ namespace __asan { index_f real_index; +memcmp_f real_memcmp; memcpy_f real_memcpy; memmove_f real_memmove; memset_f real_memset; @@ -124,6 +125,7 @@ void InitializeAsanInterceptors() { #else OVERRIDE_FUNCTION(index, WRAP(strchr)); #endif + INTERCEPT_FUNCTION(memcmp); INTERCEPT_FUNCTION(memcpy); INTERCEPT_FUNCTION(memmove); INTERCEPT_FUNCTION(memset); @@ -149,6 +151,32 @@ void InitializeAsanInterceptors() { // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT +static inline int CharCmp(unsigned char c1, unsigned char c2) { + return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; +} + +static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { + int c1_low = tolower(c1); + int c2_low = tolower(c2); + return c1_low - c2_low; +} + +int WRAP(memcmp)(const void *a1, const void *a2, size_t size) { + ENSURE_ASAN_INITED(); + unsigned char c1 = 0, c2 = 0; + const unsigned char *s1 = (const unsigned char*)a1; + const unsigned char *s2 = (const unsigned char*)a2; + size_t i; + for (i = 0; i < size; i++) { + c1 = s1[i]; + c2 = s2[i]; + if (c1 != c2) break; + } + ASAN_READ_RANGE(s1, Min(i + 1, size)); + ASAN_READ_RANGE(s2, Min(i + 1, size)); + return CharCmp(c1, c2); +} + void *WRAP(memcpy)(void *to, const void *from, size_t size) { // memcpy is called during __asan_init() from the internals // of printf(...). @@ -204,16 +232,6 @@ char *WRAP(strchr)(const char *str, int c) { return result; } -static inline int CharCmp(unsigned char c1, unsigned char c2) { - return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; -} - -static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { - int c1_low = tolower(c1); - int c2_low = tolower(c2); - return c1_low - c2_low; -} - int WRAP(strcasecmp)(const char *s1, const char *s2) { ENSURE_ASAN_INITED(); unsigned char c1, c2; diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index da5c596bae1..c8d9209805b 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -67,6 +67,7 @@ #endif #ifdef __APPLE__ +int WRAP(memcmp)(const void *a1, const void *a2, size_t size); void *WRAP(memcpy)(void *to, const void *from, size_t size); void *WRAP(memmove)(void *to, const void *from, size_t size); void *WRAP(memset)(void *block, int c, size_t size); @@ -84,6 +85,7 @@ char *WRAP(strncpy)(char *to, const char *from, size_t size); namespace __asan { typedef void* (*index_f)(const char *string, int c); +typedef int (*memcmp_f)(const void *a1, const void *a2, size_t size); typedef void* (*memcpy_f)(void *to, const void *from, size_t size); typedef void* (*memmove_f)(void *to, const void *from, size_t size); typedef void* (*memset_f)(void *block, int c, size_t size); @@ -100,6 +102,7 @@ typedef size_t (*strnlen_f)(const char *s, size_t maxlen); // __asan::real_X() holds pointer to library implementation of X(). extern index_f real_index; +extern memcmp_f real_memcmp; extern memcpy_f real_memcpy; extern memmove_f real_memmove; extern memset_f real_memset; diff --git a/compiler-rt/lib/asan/asan_stack.cc b/compiler-rt/lib/asan/asan_stack.cc index b451452aee9..4f96b8c558e 100644 --- a/compiler-rt/lib/asan/asan_stack.cc +++ b/compiler-rt/lib/asan/asan_stack.cc @@ -230,8 +230,8 @@ size_t AsanStackTrace::CompressStack(AsanStackTrace *stack, // |res| may be greater than check_stack.size, because // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames. CHECK(res >= check_stack.size); - CHECK(0 == memcmp(check_stack.trace, stack->trace, - check_stack.size * sizeof(uintptr_t))); + CHECK(0 == real_memcmp(check_stack.trace, stack->trace, + check_stack.size * sizeof(uintptr_t))); #endif return res; diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc index 41fddf37d6b..eddb28fb49b 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cc +++ b/compiler-rt/lib/asan/tests/asan_test.cc @@ -1220,6 +1220,14 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) { 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*); @@ -1292,6 +1300,30 @@ TEST(AddressSanitizer, StrNCaseCmpOOBTest) { RunStrNCmpTest(&strncasecmp); } +TEST(AddressSanitizer, MemCmpOOBTest) { + size_t size = Ident(100); + char *s1 = MallocAndMemsetString(size); + char *s2 = MallocAndMemsetString(size); + // Normal memcmp calls. + Ident(memcmp(s1, s2, size)); + Ident(memcmp(s1 + size - 1, s2 + size - 1, 1)); + Ident(memcmp(s1 - 1, s2 - 1, 0)); + // One of arguments points to not allocated memory. + EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), 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)); + // 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)); + // 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)); + free(s1); + free(s2); +} + static const char *kOverlapErrorMessage = "strcpy-param-overlap"; TEST(AddressSanitizer, StrArgsOverlapTest) { |