[compiler-rt] r234187 - sanitizer: new "strict_string_checks" run-time flag

Dmitry Vyukov dvyukov at google.com
Mon Apr 6 11:00:26 PDT 2015


Author: dvyukov
Date: Mon Apr  6 13:00:26 2015
New Revision: 234187

URL: http://llvm.org/viewvc/llvm-project?rev=234187&view=rev
Log:
sanitizer: new "strict_string_checks" run-time flag

This patch is related to Issue 346: moar string interceptors: strstr, strcasestr, strcspn, strpbrk
As was suggested in original review http://reviews.llvm.org/D6056 a new "strict_string_checks" run-time flag introduced.
The flag support applied for existing common, asan, msan and tsan interceptors. New asan tests added.

Change by Maria Guseva reviewed in http://reviews.llvm.org/D7123


Added:
    compiler-rt/trunk/test/asan/TestCases/atoi_strict.c
    compiler-rt/trunk/test/asan/TestCases/atol_strict.c
    compiler-rt/trunk/test/asan/TestCases/atoll_strict.c
    compiler-rt/trunk/test/asan/TestCases/strcat_strict.c
    compiler-rt/trunk/test/asan/TestCases/strchr_strict.c
    compiler-rt/trunk/test/asan/TestCases/strcmp_strict.c
    compiler-rt/trunk/test/asan/TestCases/strncat_strict.c
    compiler-rt/trunk/test/asan/TestCases/strtol_strict.c
    compiler-rt/trunk/test/asan/TestCases/strtoll_strict.c
Modified:
    compiler-rt/trunk/lib/asan/asan_interceptors.cc
    compiler-rt/trunk/lib/asan/tests/asan_str_test.cc
    compiler-rt/trunk/lib/msan/msan_interceptors.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.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=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Mon Apr  6 13:00:26 2015
@@ -75,6 +75,13 @@ struct AsanInterceptorContext {
 #define ASAN_WRITE_RANGE(ctx, offset, size) \
   ACCESS_MEMORY_RANGE(ctx, offset, size, true)
 
+#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n)                 \
+  ASAN_READ_RANGE((ctx), (s),                                   \
+    common_flags()->strict_string_checks ? (len) + 1 : (n))
+
+#define ASAN_READ_STRING(ctx, s, n)                             \
+  ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
 // Behavior of functions like "memcpy" or "strcpy" is undefined
 // if memory intervals overlap. We report error in this case.
 // Macro is used to avoid creation of new frames.
@@ -475,8 +482,9 @@ INTERCEPTOR(char*, strchr, const char *s
   ENSURE_ASAN_INITED();
   char *result = REAL(strchr)(str, c);
   if (flags()->replace_str) {
-    uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
-    ASAN_READ_RANGE(ctx, str, bytes_read);
+    uptr len = REAL(strlen)(str);
+    uptr bytes_read = (result ? result - str : len) + 1;
+    ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
   }
   return result;
 }
@@ -505,7 +513,7 @@ INTERCEPTOR(char*, strcat, char *to, con
     uptr from_length = REAL(strlen)(from);
     ASAN_READ_RANGE(ctx, from, from_length + 1);
     uptr to_length = REAL(strlen)(to);
-    ASAN_READ_RANGE(ctx, to, to_length);
+    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
     ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
     // If the copying actually happens, the |from| string should not overlap
     // with the resulting string starting at |to|, which has a length of
@@ -527,7 +535,7 @@ INTERCEPTOR(char*, strncat, char *to, co
     uptr copy_length = Min(size, from_length + 1);
     ASAN_READ_RANGE(ctx, from, copy_length);
     uptr to_length = REAL(strlen)(to);
-    ASAN_READ_RANGE(ctx, to, to_length);
+    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
     ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
     if (from_length > 0) {
       CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
@@ -629,23 +637,6 @@ INTERCEPTOR(uptr, strnlen, const char *s
 }
 #endif  // ASAN_INTERCEPT_STRNLEN
 
-static inline bool IsValidStrtolBase(int base) {
-  return (base == 0) || (2 <= base && base <= 36);
-}
-
-static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
-  CHECK(endptr);
-  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 = const_cast<char *>(nptr);
-  }
-  CHECK(*endptr >= nptr);
-}
-
 INTERCEPTOR(long, strtol, const char *nptr,  // NOLINT
             char **endptr, int base) {
   void *ctx;
@@ -656,13 +647,7 @@ INTERCEPTOR(long, strtol, const char *np
   }
   char *real_endptr;
   long result = REAL(strtol)(nptr, &real_endptr, base);  // NOLINT
-  if (endptr != 0) {
-    *endptr = real_endptr;
-  }
-  if (IsValidStrtolBase(base)) {
-    FixRealStrtolEndptr(nptr, &real_endptr);
-    ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
-  }
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return result;
 }
 
@@ -683,7 +668,7 @@ INTERCEPTOR(int, atoi, const char *nptr)
   // different from int). So, we just imitate this behavior.
   int result = REAL(strtol)(nptr, &real_endptr, 10);
   FixRealStrtolEndptr(nptr, &real_endptr);
-  ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
   return result;
 }
 
@@ -700,7 +685,7 @@ INTERCEPTOR(long, atol, const char *nptr
   char *real_endptr;
   long result = REAL(strtol)(nptr, &real_endptr, 10);  // NOLINT
   FixRealStrtolEndptr(nptr, &real_endptr);
-  ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
   return result;
 }
 
@@ -715,16 +700,7 @@ INTERCEPTOR(long long, strtoll, const ch
   }
   char *real_endptr;
   long long result = REAL(strtoll)(nptr, &real_endptr, base);  // NOLINT
-  if (endptr != 0) {
-    *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(ctx, nptr, (real_endptr - nptr) + 1);
-  }
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return result;
 }
 
@@ -738,7 +714,7 @@ INTERCEPTOR(long long, atoll, const char
   char *real_endptr;
   long long result = REAL(strtoll)(nptr, &real_endptr, 10);  // NOLINT
   FixRealStrtolEndptr(nptr, &real_endptr);
-  ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
   return result;
 }
 #endif  // ASAN_INTERCEPT_ATOLL_AND_STRTOLL

Modified: compiler-rt/trunk/lib/asan/tests/asan_str_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_str_test.cc?rev=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_str_test.cc (original)
+++ compiler-rt/trunk/lib/asan/tests/asan_str_test.cc Mon Apr  6 13:00:26 2015
@@ -290,9 +290,6 @@ void RunStrCmpTest(PointerToStrCmp StrCm
   Ident(StrCmp(s1, s2));
   Ident(StrCmp(s1, s2 + size - 1));
   Ident(StrCmp(s1 + size - 1, s2 + size - 1));
-  s1[size - 1] = 'z';
-  s2[size - 1] = 'x';
-  Ident(StrCmp(s1, s2));
   // One of arguments points to not allocated memory.
   EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
   EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
@@ -371,17 +368,14 @@ TEST(AddressSanitizer, StrCatOOBTest) {
   // One of arguments points to not allocated memory.
   EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
   EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
-  EXPECT_DEATH(strcat(to + to_size, from), RightOOBWriteMessage(0));
   EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
 
   // "from" is not zero-terminated.
   from[from_size - 1] = 'z';
   EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
   from[from_size - 1] = '\0';
-  // "to" is not zero-terminated.
-  memset(to, 'z', to_size);
-  EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
   // "to" is too short to fit "from".
+  memset(to, 'z', to_size);
   to[to_size - from_size + 1] = '\0';
   EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
   // length of "to" is just enough.
@@ -409,7 +403,6 @@ TEST(AddressSanitizer, StrNCatOOBTest) {
   // One of arguments points to not allocated memory.
   EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
   EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
-  EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBWriteMessage(0));
   EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
 
   memset(from, 'z', from_size);
@@ -417,8 +410,6 @@ TEST(AddressSanitizer, StrNCatOOBTest) {
   to[0] = '\0';
   // "from" is too short.
   EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
-  // "to" is not zero-terminated.
-  EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBWriteMessage(0));
   // "to" is too short to fit "from".
   to[0] = 'z';
   to[to_size - from_size + 1] = '\0';
@@ -508,20 +499,15 @@ void RunAtoiOOBTest(PointerToCallAtoi At
   EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
   // Die if a buffer doesn't have terminating NULL.
   EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
-  // Make last symbol a terminating NULL or other non-digit.
+  // Make last symbol a terminating NULL
   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), RightOOBReadMessage(0));
   array[9] = '-';
   EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
   EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
-  array[8] = '-';
-  Atoi(array);
   free(array);
 }
 
@@ -546,7 +532,6 @@ typedef void(*PointerToCallStrtol)(const
 
 void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
   char *array = MallocAndMemsetString(3);
-  char *endptr = NULL;
   array[0] = '1';
   array[1] = '2';
   array[2] = '3';
@@ -554,19 +539,12 @@ void RunStrtolOOBTest(PointerToCallStrto
   EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
   EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
   // Buffer overflow if there is no terminating null (depends on base).
-  Strtol(array, &endptr, 3);
-  EXPECT_EQ(array + 2, endptr);
   EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
   array[2] = 'z';
-  Strtol(array, &endptr, 35);
-  EXPECT_EQ(array + 2, endptr);
   EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
   // Add terminating zero to get rid of overflow.
   array[2] = '\0';
   Strtol(array, NULL, 36);
-  // Don't check for overflow if base is invalid.
-  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(Strtol(array, NULL, 0), RightOOBReadMessage(0));
@@ -574,13 +552,6 @@ void RunStrtolOOBTest(PointerToCallStrto
   EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
   array[2] = '-';
   EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
-  array[1] = '+';
-  Strtol(array, NULL, 0);
-  array[1] = array[2] = 'z';
-  Strtol(array, &endptr, 0);
-  EXPECT_EQ(array, endptr);
-  Strtol(array + 2, NULL, 0);
-  EXPECT_EQ(array, endptr);
   free(array);
 }
 

Modified: compiler-rt/trunk/lib/msan/msan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/msan/msan_interceptors.cc?rev=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/msan/msan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/msan/msan_interceptors.cc Mon Apr  6 13:00:26 2015
@@ -94,6 +94,13 @@ bool IsInInterceptorScope() {
     if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
   } while (0);
 
+#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n)               \
+  CHECK_UNPOISONED((x),                                         \
+    common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define CHECK_UNPOISONED_STRING(x, n)                           \
+    CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
+
 INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
   ENSURE_MSAN_INITED();
   SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -118,6 +125,7 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void
 
 INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
   ENSURE_MSAN_INITED();
+  CHECK_UNPOISONED_STRING(path, 0)
   SSIZE_T res = REAL(readlink)(path, buf, bufsiz);
   if (res > 0)
     __msan_unpoison(buf, res);
@@ -283,13 +291,11 @@ INTERCEPTOR(SIZE_T, strnlen, const char
   return res;
 }
 
-// FIXME: Add stricter shadow checks in str* interceptors (ex.: strcpy should
-// check the shadow of the terminating \0 byte).
-
 INTERCEPTOR(char *, strcpy, char *dest, const char *src) {  // NOLINT
   ENSURE_MSAN_INITED();
   GET_STORE_STACK_TRACE;
   SIZE_T n = REAL(strlen)(src);
+  CHECK_UNPOISONED_STRING(src + n, 0);
   char *res = REAL(strcpy)(dest, src);  // NOLINT
   CopyShadowAndOrigin(dest, src, n + 1, &stack);
   return res;
@@ -311,6 +317,7 @@ INTERCEPTOR(char *, stpcpy, char *dest,
   ENSURE_MSAN_INITED();
   GET_STORE_STACK_TRACE;
   SIZE_T n = REAL(strlen)(src);
+  CHECK_UNPOISONED_STRING(src + n, 0);
   char *res = REAL(stpcpy)(dest, src);  // NOLINT
   CopyShadowAndOrigin(dest, src, n + 1, &stack);
   return res;
@@ -322,6 +329,7 @@ INTERCEPTOR(char *, strdup, char *src) {
   // On FreeBSD strdup() leverages strlen().
   InterceptorScope interceptor_scope;
   SIZE_T n = REAL(strlen)(src);
+  CHECK_UNPOISONED_STRING(src + n, 0);
   char *res = REAL(strdup)(src);
   CopyShadowAndOrigin(res, src, n + 1, &stack);
   return res;
@@ -332,6 +340,7 @@ INTERCEPTOR(char *, __strdup, char *src)
   ENSURE_MSAN_INITED();
   GET_STORE_STACK_TRACE;
   SIZE_T n = REAL(strlen)(src);
+  CHECK_UNPOISONED_STRING(src + n, 0);
   char *res = REAL(__strdup)(src);
   CopyShadowAndOrigin(res, src, n + 1, &stack);
   return res;
@@ -381,6 +390,8 @@ INTERCEPTOR(char *, strcat, char *dest,
   GET_STORE_STACK_TRACE;
   SIZE_T src_size = REAL(strlen)(src);
   SIZE_T dest_size = REAL(strlen)(dest);
+  CHECK_UNPOISONED_STRING(src + src_size, 0);
+  CHECK_UNPOISONED_STRING(dest + dest_size, 0);
   char *res = REAL(strcat)(dest, src);  // NOLINT
   CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
   return res;
@@ -391,6 +402,7 @@ INTERCEPTOR(char *, strncat, char *dest,
   GET_STORE_STACK_TRACE;
   SIZE_T dest_size = REAL(strlen)(dest);
   SIZE_T copy_size = REAL(strnlen)(src, n);
+  CHECK_UNPOISONED_STRING(dest + dest_size, 0);
   char *res = REAL(strncat)(dest, src, n);  // NOLINT
   CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
   __msan_unpoison(dest + dest_size + copy_size, 1); // \0
@@ -667,6 +679,7 @@ static void UnpoisonEnviron() {
 
 INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
   ENSURE_MSAN_INITED();
+  CHECK_UNPOISONED_STRING(name, 0)
   int res = REAL(setenv)(name, value, overwrite);
   if (!res) UnpoisonEnviron();
   return res;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc?rev=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc Mon Apr  6 13:00:26 2015
@@ -102,6 +102,13 @@
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
 #endif
 
+#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n)       \
+    COMMON_INTERCEPTOR_READ_RANGE((ctx), (s),                       \
+      common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n)                   \
+    COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
 #ifndef COMMON_INTERCEPTOR_ON_DLOPEN
 #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {}
 #endif
@@ -159,7 +166,8 @@ UNUSED static void DeleteInterceptorMeta
 INTERCEPTOR(char*, textdomain, const char *domainname) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
-  char* domain = REAL(textdomain)(domainname);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+  char *domain = REAL(textdomain)(domainname);
   if (domain) {
     COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
   }
@@ -185,8 +193,8 @@ INTERCEPTOR(int, strcmp, const char *s1,
     c2 = (unsigned char)s2[i];
     if (c1 != c2 || c1 == '\0') break;
   }
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
   return CharCmpX(c1, c2);
 }
 
@@ -231,8 +239,8 @@ INTERCEPTOR(int, strcasecmp, const char
     c2 = (unsigned char)s2[i];
     if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
   }
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
   return CharCaseCmp(c1, c2);
 }
 
@@ -727,12 +735,12 @@ INTERCEPTOR(char *, strptime, char *s, c
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
   char *res = REAL(strptime)(s, format, tm);
-  if (res) {
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
+  if (res && tm) {
     // Do not call unpoison_tm here, because strptime does not, in fact,
     // initialize the entire struct tm. For example, tm_zone pointer is left
     // uninitialized.
-    if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
   }
   return res;
 }
@@ -1513,6 +1521,7 @@ INTERCEPTOR(int, glob, const char *patte
             __sanitizer_glob_t *pglob) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
   __sanitizer_glob_t glob_copy = {
       0,                  0,                   0,
       0,                  wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1543,6 +1552,7 @@ INTERCEPTOR(int, glob64, const char *pat
             __sanitizer_glob_t *pglob) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
   __sanitizer_glob_t glob_copy = {
       0,                  0,                   0,
       0,                  wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1689,6 +1699,7 @@ INTERCEPTOR(char *, inet_ntop, int af, c
 INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0);
   // FIXME: figure out read size based on the address family.
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
@@ -2359,6 +2370,37 @@ INTERCEPTOR(char *, get_current_dir_name
 #define INIT_GET_CURRENT_DIR_NAME
 #endif
 
+UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
+  CHECK(endptr);
+  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 = const_cast<char *>(nptr);
+  }
+  CHECK(*endptr >= nptr);
+}
+
+UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr,
+                             char **endptr, char *real_endptr, int base) {
+  if (endptr != 0) {
+    *endptr = real_endptr;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  }
+  // If base has unsupported value, strtol can exit with EINVAL
+  // without reading any characters. So do additional checks only
+  // if base is valid.
+  bool is_valid_base = (base == 0) || (2 <= base && base <= 36);
+  if (is_valid_base) {
+    FixRealStrtolEndptr(nptr, &real_endptr);
+  }
+  COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ?
+                                 (real_endptr - nptr) + 1 : 0);
+}
+
+
 #if SANITIZER_INTERCEPT_STRTOIMAX
 INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
   void *ctx;
@@ -2366,8 +2408,9 @@ INTERCEPTOR(INTMAX_T, strtoimax, const c
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
-  INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
-  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  char *real_endptr;
+  INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return res;
 }
 
@@ -2377,8 +2420,9 @@ INTERCEPTOR(INTMAX_T, strtoumax, const c
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
-  INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
-  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  char *real_endptr;
+  INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return res;
 }
 
@@ -3642,6 +3686,7 @@ INTERCEPTOR(char *, tempnam, char *dir,
 INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
   COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
   return REAL(pthread_setname_np)(thread, name);
 }
@@ -4699,6 +4744,7 @@ INTERCEPTOR(int, fclose, __sanitizer_FIL
 INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+  if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
   COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag);
   void *res = REAL(dlopen)(filename, flag);
   COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc?rev=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc Mon Apr  6 13:00:26 2015
@@ -151,3 +151,5 @@ COMMON_FLAG(const char *, stack_trace_fo
             "Use DEFAULT to get default format.")
 COMMON_FLAG(bool, no_huge_pages_for_shadow, true,
             "If true, the shadow is not allowed to use huge pages. ")
+COMMON_FLAG(bool, strict_string_checks, false,
+            "If set check that string arguments are properly null-terminated")

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=234187&r1=234186&r2=234187&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Mon Apr  6 13:00:26 2015
@@ -277,6 +277,13 @@ ScopedInterceptor::~ScopedInterceptor()
 # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
 #endif
 
+#define READ_STRING_OF_LEN(thr, pc, s, len, n)                 \
+  MemoryAccessRange((thr), (pc), (uptr)(s),                         \
+    common_flags()->strict_string_checks ? (len) + 1 : (n), false)
+
+#define READ_STRING(thr, pc, s, n)                             \
+    READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n))
+
 #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
 
 struct BlockingCall {
@@ -708,8 +715,9 @@ TSAN_INTERCEPTOR(void*, memmove, void *d
 TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
   SCOPED_TSAN_INTERCEPTOR(strchr, s, c);
   char *res = REAL(strchr)(s, c);
-  uptr len = res ? (char*)res - (char*)s + 1 : internal_strlen(s) + 1;
-  MemoryAccessRange(thr, pc, (uptr)s, len, false);
+  uptr len = internal_strlen(s);
+  uptr n = res ? (char*)res - (char*)s + 1 : len + 1;
+  READ_STRING_OF_LEN(thr, pc, s, len, n);
   return res;
 }
 
@@ -717,7 +725,7 @@ TSAN_INTERCEPTOR(char*, strchrnul, char
   SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
   char *res = REAL(strchrnul)(s, c);
   uptr len = (char*)res - (char*)s + 1;
-  MemoryAccessRange(thr, pc, (uptr)s, len, false);
+  READ_STRING(thr, pc, s, len);
   return res;
 }
 
@@ -1398,6 +1406,7 @@ TSAN_INTERCEPTOR(int, sem_getvalue, void
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__xstat)(version, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
@@ -1408,9 +1417,11 @@ TSAN_INTERCEPTOR(int, __xstat, int versi
 TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
 #if SANITIZER_FREEBSD
   SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(stat)(path, buf);
 #else
   SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__xstat)(0, path, buf);
 #endif
 }
@@ -1418,6 +1429,7 @@ TSAN_INTERCEPTOR(int, stat, const char *
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__xstat64)(version, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
@@ -1428,6 +1440,7 @@ TSAN_INTERCEPTOR(int, __xstat64, int ver
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__xstat64)(0, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
@@ -1438,6 +1451,7 @@ TSAN_INTERCEPTOR(int, stat64, const char
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__lxstat)(version, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
@@ -1448,9 +1462,11 @@ TSAN_INTERCEPTOR(int, __lxstat, int vers
 TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
 #if SANITIZER_FREEBSD
   SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(lstat)(path, buf);
 #else
   SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__lxstat)(0, path, buf);
 #endif
 }
@@ -1458,6 +1474,7 @@ TSAN_INTERCEPTOR(int, lstat, const char
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__lxstat64)(version, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
@@ -1468,6 +1485,7 @@ TSAN_INTERCEPTOR(int, __lxstat64, int ve
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+  READ_STRING(thr, pc, path, 0);
   return REAL(__lxstat64)(0, path, buf);
 }
 #define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
@@ -1527,6 +1545,7 @@ TSAN_INTERCEPTOR(int, fstat64, int fd, v
 
 TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
+  READ_STRING(thr, pc, name, 0);
   int fd = REAL(open)(name, flags, mode);
   if (fd >= 0)
     FdFileCreate(thr, pc, fd);
@@ -1536,6 +1555,7 @@ TSAN_INTERCEPTOR(int, open, const char *
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
+  READ_STRING(thr, pc, name, 0);
   int fd = REAL(open64)(name, flags, mode);
   if (fd >= 0)
     FdFileCreate(thr, pc, fd);
@@ -1548,6 +1568,7 @@ TSAN_INTERCEPTOR(int, open64, const char
 
 TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
+  READ_STRING(thr, pc, name, 0);
   int fd = REAL(creat)(name, mode);
   if (fd >= 0)
     FdFileCreate(thr, pc, fd);
@@ -1557,6 +1578,7 @@ TSAN_INTERCEPTOR(int, creat, const char
 #if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
+  READ_STRING(thr, pc, name, 0);
   int fd = REAL(creat64)(name, mode);
   if (fd >= 0)
     FdFileCreate(thr, pc, fd);

Added: compiler-rt/trunk/test/asan/TestCases/atoi_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/atoi_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/atoi_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/atoi_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atoi function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+  // Last symbol is non-digit
+  memset(array, '1', 10);
+  array[9] = 'a';
+  int r = atoi(array);
+  assert(r == 111111111);
+}
+
+void test2(char *array) {
+  // Single non-digit symbol
+  array[9] = 'a';
+  int r = atoi(array + 9);
+  assert(r == 0);
+}
+
+void test3(char *array) {
+  // Incorrect number format
+  memset(array, ' ', 10);
+  array[9] = '-';
+  array[8] = '-';
+  int r = atoi(array);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array = (char*)malloc(10);
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 11
+  if (!strcmp(argv[1], "test2")) test2(array);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 2
+  if (!strcmp(argv[1], "test3")) test3(array);
+  // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK3: READ of size 11
+  free(array);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/atol_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/atol_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/atol_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/atol_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atol function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+  // Last symbol is non-digit
+  memset(array, '1', 10);
+  array[9] = 'a';
+  long r = atol(array);
+  assert(r == 111111111);
+}
+
+void test2(char *array) {
+  // Single non-digit symbol
+  array[9] = 'a';
+  long r = atol(array + 9);
+  assert(r == 0);
+}
+
+void test3(char *array) {
+  // Incorrect number format
+  memset(array, ' ', 10);
+  array[9] = '-';
+  array[8] = '-';
+  long r = atol(array);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array = (char*)malloc(10);
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 11
+  if (!strcmp(argv[1], "test2")) test2(array);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 2
+  if (!strcmp(argv[1], "test3")) test3(array);
+  // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK3: READ of size 11
+  free(array);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/atoll_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/atoll_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/atoll_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/atoll_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atoll function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+  // Last symbol is non-digit
+  memset(array, '1', 10);
+  array[9] = 'a';
+  long long r = atoll(array);
+  assert(r == 111111111);
+}
+
+void test2(char *array) {
+  // Single non-digit symbol
+  array[9] = 'a';
+  long long r = atoll(array + 9);
+  assert(r == 0);
+}
+
+void test3(char *array) {
+  // Incorrect number format
+  memset(array, ' ', 10);
+  array[9] = '-';
+  array[8] = '-';
+  long long r = atoll(array);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array = (char*)malloc(10);
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 11
+  if (!strcmp(argv[1], "test2")) test2(array);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 2
+  if (!strcmp(argv[1], "test3")) test3(array);
+  // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK3: READ of size 11
+  free(array);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strcat_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strcat_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strcat_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strcat_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,44 @@
+// Test strict_string_checks option in strcat function
+// RUN: %clang_asan %s -o %t
+// RUN: not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=false not  %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-STRICT --check-prefix=CHECK1
+// RUN: not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=false not  %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-STRICT --check-prefix=CHECK2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *to, int to_size, char *from) {
+  // One of arguments points to not allocated memory.
+  char* r = strcat(to + to_size, from);
+}
+
+void test2(char *to, int to_size, char *from) {
+  // "to" is not zero-terminated.
+  memset(to, 'z', to_size);
+  char* r = strcat(to, from);
+}
+
+int main(int argc, char **argv) {
+  size_t to_size = 100;
+  char *to = (char*)malloc(to_size);
+  size_t from_size = 20;
+  char *from = (char*)malloc(from_size);
+  memset(from, 'z', from_size);
+  from[from_size - 1] = '\0';
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(to, to_size, from);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1-STRICT: READ of size 1
+  // CHECK1-NONSTRICT: WRITE of size 20
+  if (!strcmp(argv[1], "test2")) test2(to, to_size, from);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2-STRICT: READ of size 101
+  // CHECK2-NONSTRICT: WRITE of size 20
+  free(to);
+  free(from);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strchr_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strchr_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strchr_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strchr_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,22 @@
+// Test strict_string_checks option in strchr function
+// RUN: %clang_asan %s -o %t && %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+  size_t size = 100;
+  char fill = 'o';
+  char *s = (char*)malloc(size);
+  memset(s, fill, size);
+  char c = 'o';
+  char* r = strchr(s, c);
+  // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK: READ of size 101
+  assert(r == s);
+  free(s);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strcmp_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strcmp_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strcmp_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strcmp_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,26 @@
+// Test strict_string_checks option in strcmp function
+// RUN: %clang_asan %s -o %t && %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+  size_t size = 100;
+  char fill = 'o';
+  char *s1 = (char*)malloc(size);
+  memset(s1, fill, size);
+  char *s2 = (char*)malloc(size);
+  memset(s2, fill, size);
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  int r = strcmp(s1, s2);
+  // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK: READ of size 101
+  assert(r == 1);
+  free(s1);
+  free(s2);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strncat_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strncat_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strncat_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strncat_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,44 @@
+// Test strict_string_checks option in strncat function
+// RUN: %clang_asan %s -o %t
+// RUN: not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=false not  %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-STRICT --check-prefix=CHECK1
+// RUN: not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=false not  %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-STRICT --check-prefix=CHECK2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *to, int to_size, char *from) {
+  // One of arguments points to not allocated memory.
+  char* r = strncat(to + to_size, from, 2);
+}
+
+void test2(char *to, int to_size, char *from) {
+  // "to" is not zero-terminated.
+  memset(to, 'z', to_size);
+  char* r = strncat(to, from, 1);
+}
+
+int main(int argc, char **argv) {
+  size_t to_size = 100;
+  char *to = (char*)malloc(to_size);
+  size_t from_size = 20;
+  char *from = (char*)malloc(from_size);
+  memset(from, 'z', from_size);
+  from[from_size - 1] = '\0';
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(to, to_size, from);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1-STRICT: READ of size 1
+  // CHECK1-NONSTRICT: WRITE of size 3
+  if (!strcmp(argv[1], "test2")) test2(to, to_size, from);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2-STRICT: READ of size 101
+  // CHECK2-NONSTRICT: WRITE of size 2
+  free(to);
+  free(from);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strtol_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strtol_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strtol_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strtol_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,111 @@
+// Test strict_string_checks option in strtol function
+// RUN: %clang_asan -DTEST1 %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test7 2>&1 | FileCheck %s --check-prefix=CHECK7
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  long r = strtol(array, &endptr, 3);
+  assert(array + 2 == endptr);
+  assert(r == 5);
+}
+
+void test2(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  array[2] = 'z';
+  long r = strtol(array, &endptr, 35);
+  assert(array + 2 == endptr);
+  assert(r == 37);
+}
+
+void test3(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  long r = strtol(array - 1, NULL, -1);
+  assert(r == 0);
+}
+
+void test4(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  long r = strtol(array + 3, NULL, 1);
+  assert(r == 0);
+}
+
+void test5(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = '+';
+  array[2] = '-';
+  long r = strtol(array, NULL, 0);
+  assert(r == 0);
+}
+
+void test6(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = array[2] = 'z';
+  long r = strtol(array, &endptr, 0);
+  assert(array == endptr);
+  assert(r == 0);
+}
+
+void test7(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[2] = 'z';
+  long r = strtol(array + 2, NULL, 0);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array = (char*)malloc(3);
+  char *endptr = NULL;
+  array[0] = '1';
+  array[1] = '2';
+  array[2] = '3';
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array, endptr);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 4
+  if (!strcmp(argv[1], "test2")) test2(array, endptr);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 4
+  if (!strcmp(argv[1], "test3")) test3(array, endptr);
+  // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK3: READ of size 5
+  if (!strcmp(argv[1], "test4")) test4(array, endptr);
+  // CHECK4: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK4: READ of size 1
+  if (!strcmp(argv[1], "test5")) test5(array, endptr);
+  // CHECK5: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK5: READ of size 4
+  if (!strcmp(argv[1], "test6")) test6(array, endptr);
+  // CHECK6: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK6: READ of size 4
+  if (!strcmp(argv[1], "test7")) test7(array, endptr);
+  // CHECK7: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK7: READ of size 2
+  free(array);
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/strtoll_strict.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strtoll_strict.c?rev=234187&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/strtoll_strict.c (added)
+++ compiler-rt/trunk/test/asan/TestCases/strtoll_strict.c Mon Apr  6 13:00:26 2015
@@ -0,0 +1,111 @@
+// Test strict_string_checks option in strtoll function
+// RUN: %clang_asan -DTEST1 %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test7 2>&1 | FileCheck %s --check-prefix=CHECK7
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  long long r = strtoll(array, &endptr, 3);
+  assert(array + 2 == endptr);
+  assert(r == 5);
+}
+
+void test2(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  array[2] = 'z';
+  long long r = strtoll(array, &endptr, 35);
+  assert(array + 2 == endptr);
+  assert(r == 37);
+}
+
+void test3(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  long long r = strtoll(array - 1, NULL, -1);
+  assert(r == 0);
+}
+
+void test4(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  long long r = strtoll(array + 3, NULL, 1);
+  assert(r == 0);
+}
+
+void test5(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = '+';
+  array[2] = '-';
+  long long r = strtoll(array, NULL, 0);
+  assert(r == 0);
+}
+
+void test6(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = array[2] = 'z';
+  long long r = strtoll(array, &endptr, 0);
+  assert(array == endptr);
+  assert(r == 0);
+}
+
+void test7(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[2] = 'z';
+  long long r = strtoll(array + 2, NULL, 0);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array = (char*)malloc(3);
+  char *endptr = NULL;
+  array[0] = '1';
+  array[1] = '2';
+  array[2] = '3';
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array, endptr);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 4
+  if (!strcmp(argv[1], "test2")) test2(array, endptr);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 4
+  if (!strcmp(argv[1], "test3")) test3(array, endptr);
+  // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK3: READ of size 5
+  if (!strcmp(argv[1], "test4")) test4(array, endptr);
+  // CHECK4: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK4: READ of size 1
+  if (!strcmp(argv[1], "test5")) test5(array, endptr);
+  // CHECK5: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK5: READ of size 4
+  if (!strcmp(argv[1], "test6")) test6(array, endptr);
+  // CHECK6: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK6: READ of size 4
+  if (!strcmp(argv[1], "test7")) test7(array, endptr);
+  // CHECK7: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK7: READ of size 2
+  free(array);
+  return 0;
+}





More information about the llvm-commits mailing list