forked from OSchip/llvm-project
parent
c29ebc36b1
commit
0a4f8dc0cb
|
@ -89,6 +89,7 @@ size_t strnlen(const char *s, size_t maxlen);
|
|||
# endif
|
||||
|
||||
// stdlib.h
|
||||
long strtol(const char *nptr, char **endptr, int base); // NOLINT
|
||||
# if ASAN_INTERCEPT_STRTOLL
|
||||
long long strtoll(const char *nptr, char **endptr, int base); // NOLINT
|
||||
# endif
|
||||
|
@ -659,15 +660,24 @@ INTERCEPTOR(size_t, strnlen, const char *s, size_t maxlen) {
|
|||
}
|
||||
#endif // ASAN_INTERCEPT_STRNLEN
|
||||
|
||||
# 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;
|
||||
static inline bool IsValidStrtolBase(int base) {
|
||||
return (base == 0) || (2 <= base && base <= 36);
|
||||
}
|
||||
|
||||
static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
|
||||
CHECK(endptr != NULL);
|
||||
if (nptr == *endptr) {
|
||||
// No digits were found at strtol call, we need to find out the last
|
||||
// symbol accessed by strtoll on our own.
|
||||
// We get this symbol by skipping leading blanks and optional +/- sign.
|
||||
while (IsSpace(*nptr)) nptr++;
|
||||
if (*nptr == '+' || *nptr == '-') nptr++;
|
||||
*endptr = (char*)nptr;
|
||||
}
|
||||
CHECK(*endptr >= nptr);
|
||||
}
|
||||
|
||||
# if ASAN_INTERCEPT_STRTOLL
|
||||
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
ENSURE_ASAN_INITED();
|
||||
|
@ -682,19 +692,32 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
|
|||
// 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);
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_STRTOLL
|
||||
|
||||
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!FLAG_replace_str) {
|
||||
return REAL(strtol)(nptr, endptr, base);
|
||||
}
|
||||
char *real_endptr;
|
||||
long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
|
||||
if (endptr != NULL) {
|
||||
*endptr = real_endptr;
|
||||
}
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
INTERCEPTOR_WINAPI(DWORD, CreateThread,
|
||||
void* security, size_t stack_size,
|
||||
|
@ -754,6 +777,7 @@ void InitializeAsanInterceptors() {
|
|||
CHECK(INTERCEPT_FUNCTION(strnlen));
|
||||
#endif
|
||||
|
||||
CHECK(INTERCEPT_FUNCTION(strtol));
|
||||
#if ASAN_INTERCEPT_STRTOLL
|
||||
CHECK(INTERCEPT_FUNCTION(strtoll));
|
||||
#endif
|
||||
|
|
|
@ -1349,46 +1349,61 @@ TEST(AddressSanitizer, StrArgsOverlapTest) {
|
|||
free(str);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrtollOOBTest) {
|
||||
void CallStrtol(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtol(nptr, endptr, base));
|
||||
}
|
||||
void CallStrtoll(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtoll(nptr, endptr, base));
|
||||
}
|
||||
typedef void(*PointerToCallStrtol)(const char*, char**, int);
|
||||
|
||||
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
|
||||
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));
|
||||
EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0));
|
||||
EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1));
|
||||
// Buffer overflow if there is no terminating null (depends on base).
|
||||
Ident(strtoll(array, &endptr, 3));
|
||||
Strtol(array, &endptr, 3);
|
||||
EXPECT_EQ(array + 2, endptr);
|
||||
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
array[2] = 'z';
|
||||
Ident(strtoll(array, &endptr, 35));
|
||||
Strtol(array, &endptr, 35);
|
||||
EXPECT_EQ(array + 2, endptr);
|
||||
EXPECT_DEATH(strtoll(array, NULL, 36), RightOOBErrorMessage(0));
|
||||
EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBErrorMessage(0));
|
||||
// Add terminating zero to get rid of overflow.
|
||||
array[2] = '\0';
|
||||
Ident(strtoll(array, NULL, 36));
|
||||
Strtol(array, NULL, 36);
|
||||
// Don't check for overflow if base is invalid.
|
||||
Ident(strtoll(array - 1, NULL, -1));
|
||||
Ident(strtoll(array + 3, NULL, 1));
|
||||
Strtol(array - 1, NULL, -1);
|
||||
Strtol(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));
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
array[2] = '+';
|
||||
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
array[2] = '-';
|
||||
EXPECT_DEATH(strtoll(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
|
||||
array[1] = '+';
|
||||
Ident(strtoll(array, NULL, 0));
|
||||
Strtol(array, NULL, 0);
|
||||
array[1] = array[2] = 'z';
|
||||
Ident(strtoll(array, &endptr, 0));
|
||||
Strtol(array, &endptr, 0);
|
||||
EXPECT_EQ(array, endptr);
|
||||
Ident(strtoll(array + 2, NULL, 0));
|
||||
Strtol(array + 2, NULL, 0);
|
||||
EXPECT_EQ(array, endptr);
|
||||
delete array;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrtollOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtoll);
|
||||
}
|
||||
TEST(AddressSanitizer, StrtolOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtol);
|
||||
}
|
||||
|
||||
// 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