forked from OSchip/llvm-project
parent
03c970e2fe
commit
c8efe828a9
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue