diff options
author | Alexey Samsonov <samsonov@google.com> | 2012-03-29 08:04:35 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2012-03-29 08:04:35 +0000 |
commit | b33c87bbb9056305b57aeed7dd1df43f8c4d085e (patch) | |
tree | 1ef3e23de9ce244868e58f4615895324ef3ba8ce /compiler-rt | |
parent | a0a603e5823b6a7534033ba550ff7377ddeb46b9 (diff) | |
download | bcm5719-llvm-b33c87bbb9056305b57aeed7dd1df43f8c4d085e.tar.gz bcm5719-llvm-b33c87bbb9056305b57aeed7dd1df43f8c4d085e.zip |
[ASan] interceptors for atoi/atol/atoll
llvm-svn: 153637
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 76 | ||||
-rw-r--r-- | compiler-rt/lib/asan/tests/asan_test.cc | 48 |
2 files changed, 107 insertions, 17 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 8228121374a..a11601994e4 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -27,9 +27,9 @@ // Use macro to describe if specific function should be // intercepted on a given platform. #if !defined(_WIN32) -# define ASAN_INTERCEPT_STRTOLL 1 +# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1 #else -# define ASAN_INTERCEPT_STRTOLL 0 +# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0 #endif #if !defined(__APPLE__) @@ -89,8 +89,11 @@ size_t strnlen(const char *s, size_t maxlen); # endif // stdlib.h +int atoi(const char *nptr); +long atol(const char *nptr); // NOLINT long strtol(const char *nptr, char **endptr, int base); // NOLINT -# if ASAN_INTERCEPT_STRTOLL +# if ASAN_INTERCEPT_ATOLL_AND_STRTOLL +long long atoll(const char *nptr); // NOLINT long long strtoll(const char *nptr, char **endptr, int base); // NOLINT # endif @@ -677,40 +680,67 @@ static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) { CHECK(*endptr >= nptr); } -# if ASAN_INTERCEPT_STRTOLL -INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT +INTERCEPTOR(long, strtol, const char *nptr, // NOLINT char **endptr, int base) { ENSURE_ASAN_INITED(); if (!FLAG_replace_str) { - return REAL(strtoll)(nptr, endptr, base); + return REAL(strtol)(nptr, endptr, base); } char *real_endptr; - long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT + long result = REAL(strtol)(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 (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 +INTERCEPTOR(int, atoi, const char *nptr) { + ENSURE_ASAN_INITED(); + if (!FLAG_replace_str) { + return REAL(atoi)(nptr); + } + char *real_endptr; + // "man atoi" tells that behavior of atoi(nptr) is the same as + // strtol(nptr, NULL, 10), i.e. it sets errno to ERANGE if the + // parsed integer can't be stored in *long* type (even if it's + // different from int). So, we just imitate this behavior. + int result = REAL(strtol)(nptr, &real_endptr, 10); + FixRealStrtolEndptr(nptr, &real_endptr); + ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1); + return result; +} + +INTERCEPTOR(long, atol, const char *nptr) { // NOLINT + ENSURE_ASAN_INITED(); + if (!FLAG_replace_str) { + return REAL(atol)(nptr); + } + char *real_endptr; + long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT + FixRealStrtolEndptr(nptr, &real_endptr); + ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1); + return result; +} + +#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL +INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT char **endptr, int base) { ENSURE_ASAN_INITED(); if (!FLAG_replace_str) { - return REAL(strtol)(nptr, endptr, base); + return REAL(strtoll)(nptr, endptr, base); } char *real_endptr; - long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT + 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 (IsValidStrtolBase(base)) { FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1); @@ -718,6 +748,19 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT return result; } +INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT + ENSURE_ASAN_INITED(); + if (!FLAG_replace_str) { + return REAL(atoll)(nptr); + } + char *real_endptr; + long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT + FixRealStrtolEndptr(nptr, &real_endptr); + ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1); + return result; +} +#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL + #if defined(_WIN32) INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, size_t stack_size, @@ -777,8 +820,11 @@ void InitializeAsanInterceptors() { CHECK(INTERCEPT_FUNCTION(strnlen)); #endif + CHECK(INTERCEPT_FUNCTION(atoi)); + CHECK(INTERCEPT_FUNCTION(atol)); CHECK(INTERCEPT_FUNCTION(strtol)); -#if ASAN_INTERCEPT_STRTOLL +#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL + CHECK(INTERCEPT_FUNCTION(atoll)); CHECK(INTERCEPT_FUNCTION(strtoll)); #endif diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc index b611d52c744..0dfffb21211 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cc +++ b/compiler-rt/lib/asan/tests/asan_test.cc @@ -986,11 +986,14 @@ TEST(AddressSanitizer, StrLenOOBTest) { free(heap_string); } -static inline char* MallocAndMemsetString(size_t size) { +static inline char* MallocAndMemsetString(size_t size, char ch) { char *s = Ident((char*)malloc(size)); - memset(s, 'z', size); + memset(s, ch, size); return s; } +static inline char* MallocAndMemsetString(size_t size) { + return MallocAndMemsetString(size, 'z'); +} #ifndef __APPLE__ TEST(AddressSanitizer, StrNLenOOBTest) { @@ -1349,6 +1352,47 @@ TEST(AddressSanitizer, StrArgsOverlapTest) { free(str); } +void CallAtoi(const char *nptr) { + Ident(atoi(nptr)); +} +void CallAtol(const char *nptr) { + Ident(atol(nptr)); +} +void CallAtoll(const char *nptr) { + Ident(atoll(nptr)); +} +typedef void(*PointerToCallAtoi)(const char*); + +void RunAtoiOOBTest(PointerToCallAtoi Atoi) { + char *array = MallocAndMemsetString(10, '1'); + // Invalid pointer to the string. + EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1)); + EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1)); + // Die if a buffer doesn't have terminating NULL. + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + // Make last symbol a terminating NULL or other non-digit. + array[9] = '\0'; + Atoi(array); + array[9] = 'a'; + Atoi(array); + Atoi(array + 9); + // Sometimes we need to detect overflow if no digits are found. + memset(array, ' ', 10); + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + array[9] = '-'; + EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0)); + EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0)); + array[8] = '-'; + Atoi(array); + delete array; +} + +TEST(AddressSanitizer, AtoiAndFriendsOOBTest) { + RunAtoiOOBTest(&CallAtoi); + RunAtoiOOBTest(&CallAtol); + RunAtoiOOBTest(&CallAtoll); +} + void CallStrtol(const char *nptr, char **endptr, int base) { Ident(strtol(nptr, endptr, base)); } |