[asan] interceptor for memcmp. Patch by samsonov@google.com
llvm-svn: 147315
This commit is contained in:
parent
d2a0365304
commit
6579e355c0
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue