summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler-rt/lib/asan/asan_interceptors.cc52
-rw-r--r--compiler-rt/lib/asan/tests/asan_test.cc47
2 files changed, 69 insertions, 30 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc
index f10ae981a33..8228121374a 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cc
+++ b/compiler-rt/lib/asan/asan_interceptors.cc
@@ -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
diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc
index a446db000a2..b611d52c744 100644
--- a/compiler-rt/lib/asan/tests/asan_test.cc
+++ b/compiler-rt/lib/asan/tests/asan_test.cc
@@ -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
OpenPOWER on IntegriCloud