[asan] interceptor for memcmp. Patch by samsonov@google.com

llvm-svn: 147315
This commit is contained in:
Kostya Serebryany 2011-12-28 18:56:42 +00:00
parent d2a0365304
commit 6579e355c0
4 changed files with 65 additions and 12 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {