diff options
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 40 | ||||
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.h | 6 | ||||
-rw-r--r-- | compiler-rt/lib/asan/tests/asan_test.cc | 132 |
3 files changed, 130 insertions, 48 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index bac1e4d4ada..09c40c1d712 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -20,8 +20,10 @@ #include "asan_stack.h" #include "asan_stats.h" +#include <ctype.h> #include <dlfcn.h> #include <string.h> +#include <strings.h> namespace __asan { @@ -29,11 +31,13 @@ index_f real_index; memcpy_f real_memcpy; memmove_f real_memmove; memset_f real_memset; +strcasecmp_f real_strcasecmp; strchr_f real_strchr; strcmp_f real_strcmp; strcpy_f real_strcpy; strdup_f real_strdup; strlen_f real_strlen; +strncasecmp_f real_strncasecmp; strncmp_f real_strncmp; strncpy_f real_strncpy; strnlen_f real_strnlen; @@ -123,11 +127,13 @@ void InitializeAsanInterceptors() { INTERCEPT_FUNCTION(memcpy); INTERCEPT_FUNCTION(memmove); INTERCEPT_FUNCTION(memset); + INTERCEPT_FUNCTION(strcasecmp); INTERCEPT_FUNCTION(strchr); INTERCEPT_FUNCTION(strcmp); INTERCEPT_FUNCTION(strcpy); // NOLINT INTERCEPT_FUNCTION(strdup); INTERCEPT_FUNCTION(strlen); + INTERCEPT_FUNCTION(strncasecmp); INTERCEPT_FUNCTION(strncmp); INTERCEPT_FUNCTION(strncpy); #ifndef __APPLE__ @@ -202,6 +208,26 @@ 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; + size_t i; + for (i = 0; ; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; + } + ASAN_READ_RANGE(s1, i + 1); + ASAN_READ_RANGE(s2, i + 1); + return CharCaseCmp(c1, c2); +} + int WRAP(strcmp)(const char *s1, const char *s2) { // strcmp is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. @@ -259,6 +285,20 @@ size_t WRAP(strlen)(const char *s) { return length; } +int WRAP(strncasecmp)(const char *s1, const char *s2, size_t size) { + ENSURE_ASAN_INITED(); + unsigned char c1 = 0, c2 = 0; + size_t i; + for (i = 0; i < size; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; + } + ASAN_READ_RANGE(s1, Min(i + 1, size)); + ASAN_READ_RANGE(s2, Min(i + 1, size)); + return CharCaseCmp(c1, c2); +} + int WRAP(strncmp)(const char *s1, const char *s2, size_t size) { // strncmp is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 20a2688f561..da5c596bae1 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -70,11 +70,13 @@ 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); +int WRAP(strcasecmp)(const char *s1, const char *s2); char *WRAP(strchr)(const char *string, int c); int WRAP(strcmp)(const char *s1, const char *s2); char *WRAP(strcpy)(char *to, const char *from); // NOLINT char *WRAP(strdup)(const char *s); size_t WRAP(strlen)(const char *s); +int WRAP(strncasecmp)(const char *s1, const char *s2, size_t n); int WRAP(strncmp)(const char *s1, const char *s2, size_t size); char *WRAP(strncpy)(char *to, const char *from, size_t size); #endif @@ -85,11 +87,13 @@ typedef void* (*index_f)(const char *string, int c); 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); +typedef int (*strcasecmp_f)(const char *s1, const char *s2); typedef char* (*strchr_f)(const char *str, int c); typedef int (*strcmp_f)(const char *s1, const char *s2); typedef char* (*strcpy_f)(char *to, const char *from); typedef char* (*strdup_f)(const char *s); typedef size_t (*strlen_f)(const char *s); +typedef int (*strncasecmp_f)(const char *s1, const char *s2, size_t n); typedef int (*strncmp_f)(const char *s1, const char *s2, size_t size); typedef char* (*strncpy_f)(char *to, const char *from, size_t size); typedef size_t (*strnlen_f)(const char *s, size_t maxlen); @@ -99,11 +103,13 @@ extern index_f real_index; extern memcpy_f real_memcpy; extern memmove_f real_memmove; extern memset_f real_memset; +extern strcasecmp_f real_strcasecmp; extern strchr_f real_strchr; extern strcmp_f real_strcmp; extern strcpy_f real_strcpy; extern strdup_f real_strdup; extern strlen_f real_strlen; +extern strncasecmp_f real_strncasecmp; extern strncmp_f real_strncmp; extern strncpy_f real_strncpy; extern strnlen_f real_strnlen; diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc index b924a30a941..41fddf37d6b 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cc +++ b/compiler-rt/lib/asan/tests/asan_test.cc @@ -14,6 +14,7 @@ #include <signal.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <pthread.h> #include <stdint.h> #include <setjmp.h> @@ -1050,11 +1051,16 @@ TEST(AddressSanitizer, StrLenOOBTest) { free(heap_string); } +static inline char* MallocAndMemsetString(size_t size) { + char *s = Ident((char*)malloc(size)); + memset(s, 'z', size); + return s; +} + #ifndef __APPLE__ TEST(AddressSanitizer, StrNLenOOBTest) { size_t size = Ident(123); - char *str = Ident((char*)malloc(size)); - memset(str, 'z', size); + char *str = MallocAndMemsetString(size); // Normal strnlen calls. Ident(strnlen(str - 1, 0)); Ident(strnlen(str, size)); @@ -1073,9 +1079,8 @@ TEST(AddressSanitizer, StrNLenOOBTest) { TEST(AddressSanitizer, StrDupOOBTest) { size_t size = Ident(42); - char *str = Ident((char*)malloc(size)); + char *str = MallocAndMemsetString(size); char *new_str; - memset(str, 'z', size); // Normal strdup calls. str[size - 1] = '\0'; new_str = strdup(str); @@ -1157,8 +1162,7 @@ TEST(AddressSanitizer, StrNCpyOOBTest) { typedef char*(*PointerToStrChr)(const char*, int); void RunStrChrTest(PointerToStrChr StrChr) { size_t size = Ident(100); - char *str = Ident((char*)malloc(size)); - memset(str, 'z', size); + char *str = MallocAndMemsetString(size); str[10] = 'q'; str[11] = '\0'; EXPECT_EQ(str, StrChr(str, 'z')); @@ -1181,81 +1185,113 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) { // strcmp EXPECT_EQ(0, strcmp("", "")); EXPECT_EQ(0, strcmp("abcd", "abcd")); - EXPECT_EQ(-1, strcmp("ab", "ac")); - EXPECT_EQ(-1, strcmp("abc", "abcd")); - EXPECT_EQ(1, strcmp("acc", "abc")); - EXPECT_EQ(1, strcmp("abcd", "abc")); + 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_EQ(-1, strncmp("abcde", "abcfa", 4)); - EXPECT_EQ(-1, strncmp("a", "b", 5)); - EXPECT_EQ(-1, strncmp("bc", "bcde", 4)); - EXPECT_EQ(1, strncmp("xyz", "xyy", 10)); - EXPECT_EQ(1, strncmp("baa", "aaa", 1)); - EXPECT_EQ(1, strncmp("zyx", "", 2)); -} - -static inline char* MallocAndMemsetString(size_t size) { - char *s = Ident((char*)malloc(size)); - memset(s, 'z', size); - return s; -} - -TEST(AddressSanitizer, StrCmpOOBTest) { + 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)); +} + +typedef int(*PointerToStrCmp)(const char*, const char*); +void RunStrCmpTest(PointerToStrCmp StrCmp) { size_t size = Ident(100); char *s1 = MallocAndMemsetString(size); char *s2 = MallocAndMemsetString(size); 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)); + // 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)); + 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), 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)); // 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)); + EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBErrorMessage(0)); free(s1); free(s2); } -TEST(AddressSanitizer, StrNCmpOOBTest) { +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)); + // 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)); + 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)); + 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), 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)); // 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), RightOOBErrorMessage(0)); + EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0)); free(s1); free(s2); } +TEST(AddressSanitizer, StrNCmpOOBTest) { + RunStrNCmpTest(&strncmp); +} + +TEST(AddressSanitizer, StrNCaseCmpOOBTest) { + RunStrNCmpTest(&strncasecmp); +} + static const char *kOverlapErrorMessage = "strcpy-param-overlap"; TEST(AddressSanitizer, StrArgsOverlapTest) { |