[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