forked from OSchip/llvm-project
[asan] interceptors for strcasecmp and strncasecmp. patch by samsonov@google.com
llvm-svn: 147304
This commit is contained in:
parent
8b981c2564
commit
809632e28e
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,79 +1185,111 @@ 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));
|
||||
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));
|
||||
}
|
||||
|
||||
static inline char* MallocAndMemsetString(size_t size) {
|
||||
char *s = Ident((char*)malloc(size));
|
||||
memset(s, 'z', size);
|
||||
return s;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCmpOOBTest) {
|
||||
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, 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));
|
||||
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), 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));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCmpOOBTest) {
|
||||
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), 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));
|
||||
free(s1);
|
||||
free(s2);
|
||||
RunStrNCmpTest(&strncmp);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
|
||||
RunStrNCmpTest(&strncasecmp);
|
||||
}
|
||||
|
||||
static const char *kOverlapErrorMessage = "strcpy-param-overlap";
|
||||
|
|
Loading…
Reference in New Issue