[llvm-commits] [compiler-rt] r153376 - in /compiler-rt/trunk/lib/asan: asan_interceptors.cc tests/asan_test.cc
Alexey Samsonov
samsonov at google.com
Sat Mar 24 01:39:15 PDT 2012
Author: samsonov
Date: Sat Mar 24 03:39:14 2012
New Revision: 153376
URL: http://llvm.org/viewvc/llvm-project?rev=153376&view=rev
Log:
[ASan] add interceptor for strtoll
Modified:
compiler-rt/trunk/lib/asan/asan_interceptors.cc
compiler-rt/trunk/lib/asan/tests/asan_test.cc
Modified: compiler-rt/trunk/lib/asan/asan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.cc?rev=153376&r1=153375&r2=153376&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Sat Mar 24 03:39:14 2012
@@ -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 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 @@
}
#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 @@
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)
Modified: compiler-rt/trunk/lib/asan/tests/asan_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test.cc?rev=153376&r1=153375&r2=153376&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test.cc (original)
+++ compiler-rt/trunk/lib/asan/tests/asan_test.cc Sat Mar 24 03:39:14 2012
@@ -1349,6 +1349,46 @@
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
More information about the llvm-commits
mailing list