[ASan] add interceptor for strtoll

llvm-svn: 153376
This commit is contained in:
Alexey Samsonov 2012-03-24 08:39:14 +00:00
parent 03c970e2fe
commit c8efe828a9
2 changed files with 93 additions and 0 deletions

View File

@ -24,6 +24,14 @@
#include <new>
// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !defined(_WIN32)
# define ASAN_INTERCEPT_STRTOLL 1
#else
# define ASAN_INTERCEPT_STRTOLL 0
#endif // ASAN_WINDOWS
// Use extern declarations of intercepted functions on Mac and Windows
// to avoid including system headers.
#if defined(__APPLE__) || (defined(_WIN32) && !defined(_DLL))
@ -68,6 +76,11 @@ size_t strlen(const char *s);
size_t strnlen(const char *s, size_t maxlen);
# endif
// stdlib.h
# if ASAN_INTERCEPT_STRTOLL
long long strtoll(const char *nptr, char **endptr, int base); // NOLINT
# endif
// Windows threads.
# if defined(_WIN32)
__declspec(dllimport)
@ -635,6 +648,42 @@ INTERCEPTOR(size_t, strnlen, const char *s, size_t maxlen) {
}
#endif
# if ASAN_INTERCEPT_STRTOLL
// Returns pointer to first character of "nptr" after skipping
// leading blanks and optional +/- sign.
static char *SkipBlanksAndSign(const char *nptr) {
while (IsSpace(*nptr)) nptr++;
if (*nptr == '+' || *nptr == '-') nptr++;
return (char*)nptr;
}
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
char **endptr, int base) {
ENSURE_ASAN_INITED();
if (!FLAG_replace_str) {
return REAL(strtoll)(nptr, endptr, base);
}
char *real_endptr;
long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
if (endptr != NULL) {
*endptr = real_endptr;
}
// If base has unsupported value, strtoll can exit with EINVAL
// without reading any characters. So do additional checks only
// if base is valid.
if (base == 0 || (2 <= base && base <= 36)) {
if (real_endptr == nptr) {
// No digits were found, find out the last symbol read by strtoll
// on our own.
real_endptr = SkipBlanksAndSign(nptr);
}
CHECK(real_endptr >= nptr);
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
}
return result;
}
#endif // ASAN_INTERCEPT_STRTOLL
#if defined(_WIN32)
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, size_t stack_size,
@ -694,6 +743,10 @@ void InitializeAsanInterceptors() {
CHECK(INTERCEPT_FUNCTION(strnlen));
#endif
#if ASAN_INTERCEPT_STRTOLL
CHECK(INTERCEPT_FUNCTION(strtoll));
#endif
// Intecept signal- and jump-related functions.
CHECK(INTERCEPT_FUNCTION(longjmp));
#if !defined(ANDROID) && !defined(_WIN32)

View File

@ -1349,6 +1349,46 @@ TEST(AddressSanitizer, StrArgsOverlapTest) {
free(str);
}
TEST(AddressSanitizer, StrtollOOBTest) {
char *array = MallocAndMemsetString(3);
char *endptr = NULL;
array[0] = '1';
array[1] = '2';
array[2] = '3';
// Invalid pointer to the string.
EXPECT_DEATH(strtoll(array + 3, NULL, 0), RightOOBErrorMessage(0));
EXPECT_DEATH(strtoll(array - 1, NULL, 0), LeftOOBErrorMessage(1));
// Buffer overflow if there is no terminating null (depends on base).
Ident(strtoll(array, &endptr, 3));
EXPECT_EQ(array + 2, endptr);
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
array[2] = 'z';
Ident(strtoll(array, &endptr, 35));
EXPECT_EQ(array + 2, endptr);
EXPECT_DEATH(strtoll(array, NULL, 36), RightOOBErrorMessage(0));
// Add terminating zero to get rid of overflow.
array[2] = '\0';
Ident(strtoll(array, NULL, 36));
// Don't check for overflow if base is invalid.
Ident(strtoll(array - 1, NULL, -1));
Ident(strtoll(array + 3, NULL, 1));
// Sometimes we need to detect overflow if no digits are found.
array[0] = array[1] = array[2] = ' ';
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
array[2] = '+';
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
array[2] = '-';
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
array[1] = '+';
Ident(strtoll(array, NULL, 0));
array[1] = array[2] = 'z';
Ident(strtoll(array, &endptr, 0));
EXPECT_EQ(array, endptr);
Ident(strtoll(array + 2, NULL, 0));
EXPECT_EQ(array, endptr);
delete array;
}
// At the moment we instrument memcpy/memove/memset calls at compile time so we
// can't handle OOB error if these functions are called by pointer, see disabled
// MemIntrinsicCallByPointerTest below