[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