From 0ca65fd83d509c7ebb8f37df5ecfe27fa66905e3 Mon Sep 17 00:00:00 2001 From: Yury Gribov Date: Thu, 28 May 2015 09:24:33 +0000 Subject: [PATCH] [sanitizer] More string interceptors: strstr, strcasestr, strspn, strcspn, strpbrk. Patch by Maria Guseva. Differential Revision: http://reviews.llvm.org/D9017 llvm-svn: 238406 --- .../sanitizer_common_interceptors.inc | 95 +++++++++++++++++++ .../lib/sanitizer_common/sanitizer_flags.inc | 9 ++ .../sanitizer_platform_interceptors.h | 4 + compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 11 --- .../test/asan/TestCases/strcasestr-1.c | 23 +++++ .../test/asan/TestCases/strcasestr-2.c | 23 +++++ .../test/asan/TestCases/strcasestr_strict.c | 28 ++++++ compiler-rt/test/asan/TestCases/strcspn-1.c | 19 ++++ compiler-rt/test/asan/TestCases/strcspn-2.c | 19 ++++ .../test/asan/TestCases/strcspn_strict.c | 26 +++++ compiler-rt/test/asan/TestCases/strpbrk-1.c | 19 ++++ compiler-rt/test/asan/TestCases/strpbrk-2.c | 19 ++++ .../test/asan/TestCases/strpbrk_strict.c | 25 +++++ compiler-rt/test/asan/TestCases/strspn-1.c | 19 ++++ compiler-rt/test/asan/TestCases/strspn-2.c | 19 ++++ .../test/asan/TestCases/strspn_strict.c | 25 +++++ compiler-rt/test/asan/TestCases/strstr-1.c | 19 ++++ compiler-rt/test/asan/TestCases/strstr-2.c | 19 ++++ .../test/asan/TestCases/strstr_strict.c | 25 +++++ .../sanitizer_common/TestCases/strcasestr.c | 16 ++++ .../test/sanitizer_common/TestCases/strcspn.c | 13 +++ .../test/sanitizer_common/TestCases/strpbrk.c | 14 +++ .../test/sanitizer_common/TestCases/strspn.c | 13 +++ .../test/sanitizer_common/TestCases/strstr.c | 12 +++ 24 files changed, 503 insertions(+), 11 deletions(-) create mode 100644 compiler-rt/test/asan/TestCases/strcasestr-1.c create mode 100644 compiler-rt/test/asan/TestCases/strcasestr-2.c create mode 100644 compiler-rt/test/asan/TestCases/strcasestr_strict.c create mode 100644 compiler-rt/test/asan/TestCases/strcspn-1.c create mode 100644 compiler-rt/test/asan/TestCases/strcspn-2.c create mode 100644 compiler-rt/test/asan/TestCases/strcspn_strict.c create mode 100644 compiler-rt/test/asan/TestCases/strpbrk-1.c create mode 100644 compiler-rt/test/asan/TestCases/strpbrk-2.c create mode 100644 compiler-rt/test/asan/TestCases/strpbrk_strict.c create mode 100644 compiler-rt/test/asan/TestCases/strspn-1.c create mode 100644 compiler-rt/test/asan/TestCases/strspn-2.c create mode 100644 compiler-rt/test/asan/TestCases/strspn_strict.c create mode 100644 compiler-rt/test/asan/TestCases/strstr-1.c create mode 100644 compiler-rt/test/asan/TestCases/strstr-2.c create mode 100644 compiler-rt/test/asan/TestCases/strstr_strict.c create mode 100644 compiler-rt/test/sanitizer_common/TestCases/strcasestr.c create mode 100644 compiler-rt/test/sanitizer_common/TestCases/strcspn.c create mode 100644 compiler-rt/test/sanitizer_common/TestCases/strpbrk.c create mode 100644 compiler-rt/test/sanitizer_common/TestCases/strspn.c create mode 100644 compiler-rt/test/sanitizer_common/TestCases/strstr.c diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 4df015408fb0..ee21ccfcdae9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -271,6 +271,97 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) { #define INIT_STRNCASECMP #endif +#if SANITIZER_INTERCEPT_STRSTR || SANITIZER_INTERCEPT_STRCASESTR +static inline void StrstrCheck(void *ctx, char *r, const char *s1, + const char *s2) { + uptr len1 = REAL(strlen)(s1); + uptr len2 = REAL(strlen)(s2); + COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1, + r ? r - s1 + len2 : len1 + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); +} +#endif + +#if SANITIZER_INTERCEPT_STRSTR +INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strstr(s1, s2); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strstr, s1, s2); + char *r = REAL(strstr)(s1, s2); + if (common_flags()->intercept_strstr) + StrstrCheck(ctx, r, s1, s2); + return r; +} + +#define INIT_STRSTR COMMON_INTERCEPT_FUNCTION(strstr); +#else +#define INIT_STRSTR +#endif + +#if SANITIZER_INTERCEPT_STRCASESTR +INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2); + char *r = REAL(strcasestr)(s1, s2); + if (common_flags()->intercept_strstr) + StrstrCheck(ctx, r, s1, s2); + return r; +} + +#define INIT_STRCASESTR COMMON_INTERCEPT_FUNCTION(strcasestr); +#else +#define INIT_STRCASESTR +#endif + +#if SANITIZER_INTERCEPT_STRSPN +INTERCEPTOR(SIZE_T, strspn, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strspn, s1, s2); + SIZE_T r = REAL(strspn)(s1, s2); + if (common_flags()->intercept_strspn) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); + } + return r; +} + +INTERCEPTOR(SIZE_T, strcspn, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcspn, s1, s2); + SIZE_T r = REAL(strcspn)(s1, s2); + if (common_flags()->intercept_strspn) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); + } + return r; +} + +#define INIT_STRSPN \ + COMMON_INTERCEPT_FUNCTION(strspn); \ + COMMON_INTERCEPT_FUNCTION(strcspn); +#else +#define INIT_STRSPN +#endif + +#if SANITIZER_INTERCEPT_STRPBRK +INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strpbrk, s1, s2); + char *r = REAL(strpbrk)(s1, s2); + if (common_flags()->intercept_strpbrk) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, + r ? r - s1 + 1 : REAL(strlen)(s1) + 1); + } + return r; +} + +#define INIT_STRPBRK COMMON_INTERCEPT_FUNCTION(strpbrk); +#else +#define INIT_STRPBRK +#endif + #if SANITIZER_INTERCEPT_MEMCHR INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { void *ctx; @@ -4874,6 +4965,10 @@ static void InitializeCommonInterceptors() { INIT_STRNCMP; INIT_STRCASECMP; INIT_STRNCASECMP; + INIT_STRSTR; + INIT_STRCASESTR; + INIT_STRSPN; + INIT_STRPBRK; INIT_MEMCHR; INIT_MEMRCHR; INIT_READ; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 53c97b635b44..c713feda752d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -154,3 +154,12 @@ 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") +COMMON_FLAG(bool, intercept_strstr, true, + "If set, uses custom wrappers for strstr and strcasestr functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strspn, true, + "If set, uses custom wrappers for strspn and strcspn function " + "to find more errors.") +COMMON_FLAG(bool, intercept_strpbrk, true, + "If set, uses custom wrappers for strpbrk function " + "to find more errors.") diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 9b3e99b7bc81..8142be5c99b9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -54,6 +54,10 @@ #endif #define SANITIZER_INTERCEPT_STRCMP 1 +#define SANITIZER_INTERCEPT_STRSTR 1 +#define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRSPN 1 +#define SANITIZER_INTERCEPT_STRPBRK 1 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MEMCHR 1 diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index b47332dc3e93..ca3be644af15 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -659,16 +659,6 @@ TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { return REAL(strncpy)(dst, src, n); } -TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) { - SCOPED_TSAN_INTERCEPTOR(strstr, s1, s2); - const char *res = REAL(strstr)(s1, s2); - uptr len1 = internal_strlen(s1); - uptr len2 = internal_strlen(s2); - MemoryAccessRange(thr, pc, (uptr)s1, len1 + 1, false); - MemoryAccessRange(thr, pc, (uptr)s2, len2 + 1, false); - return res; -} - TSAN_INTERCEPTOR(char*, strdup, const char *str) { SCOPED_TSAN_INTERCEPTOR(strdup, str); // strdup will call malloc, so no instrumentation is required here. @@ -2472,7 +2462,6 @@ void InitializeInterceptors() { TSAN_INTERCEPT(strrchr); TSAN_INTERCEPT(strcpy); // NOLINT TSAN_INTERCEPT(strncpy); - TSAN_INTERCEPT(strstr); TSAN_INTERCEPT(strdup); TSAN_INTERCEPT(pthread_create); diff --git a/compiler-rt/test/asan/TestCases/strcasestr-1.c b/compiler-rt/test/asan/TestCases/strcasestr-1.c new file mode 100644 index 000000000000..642549e2555b --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcasestr-1.c @@ -0,0 +1,23 @@ +// Test haystack overflow in strcasestr function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strstr asan option +// RUN: ASAN_OPTIONS=intercept_strstr=false %run %t 2>&1 + +// There's no interceptor for strcasestr on Windows +// XFAIL: win32 + +#define _GNU_SOURCE +#include +#include + +int main(int argc, char **argv) { + char *r = 0; + char s2[] = "c"; + char s1[] = {'a', 'b'}; + char s3 = 0; + r = strcasestr(s1, s2); + // CHECK:'s{{[1|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == 0); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strcasestr-2.c b/compiler-rt/test/asan/TestCases/strcasestr-2.c new file mode 100644 index 000000000000..a1b59885e60a --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcasestr-2.c @@ -0,0 +1,23 @@ +// Test needle overflow in strcasestr function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strstr asan option +// RUN: ASAN_OPTIONS=intercept_strstr=false %run %t 2>&1 + +// There's no interceptor for strcasestr on Windows +// XFAIL: win32 + +#define _GNU_SOURCE +#include +#include + +int main(int argc, char **argv) { + char *r = 0; + char s1[] = "ab"; + char s2[] = {'c'}; + char s3 = 0; + r = strcasestr(s1, s2); + assert(r == 0); + // CHECK:'s{{[2|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strcasestr_strict.c b/compiler-rt/test/asan/TestCases/strcasestr_strict.c new file mode 100644 index 000000000000..9448bb3d0566 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcasestr_strict.c @@ -0,0 +1,28 @@ +// Test strict_string_checks option in strcasestr 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 + +// There's no interceptor for strcasestr on Windows +// XFAIL: win32 + +#define _GNU_SOURCE +#include +#include +#include + +int main(int argc, char **argv) { + size_t size = 100; + char *s1 = (char*)malloc(size); + char *s2 = (char*)malloc(size); + memset(s1, 'o', size); + memset(s2, 'O', size); + s2[size - 1]='\0'; + char* r = strcasestr(s1, s2); + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: READ of size 101 + assert(r == s1); + free(s1); + free(s2); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strcspn-1.c b/compiler-rt/test/asan/TestCases/strcspn-1.c new file mode 100644 index 000000000000..edbfa25921ea --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcspn-1.c @@ -0,0 +1,19 @@ +// Test string s1 overflow in strcspn function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strspn asan option +// RUN: ASAN_OPTIONS=intercept_strspn=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s2[] = "ab"; + char s1[] = {'c', 'd'}; + char s3 = 0; + r = strcspn(s1, s2); + // CHECK:'s{{[1|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r >= sizeof(s1)); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strcspn-2.c b/compiler-rt/test/asan/TestCases/strcspn-2.c new file mode 100644 index 000000000000..c4e2691e5b14 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcspn-2.c @@ -0,0 +1,19 @@ +// Test stopset overflow in strcspn function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strcspn asan option +// RUN: ASAN_OPTIONS=intercept_strspn=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s1[] = "ab"; + char s2[] = {'c', 'd'}; + char s3 = 0; + r = strcspn(s1, s2); + // CHECK:'s{{[2|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == sizeof(s1) - 1); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strcspn_strict.c b/compiler-rt/test/asan/TestCases/strcspn_strict.c new file mode 100644 index 000000000000..384615288bcc --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strcspn_strict.c @@ -0,0 +1,26 @@ +// Test strict_string_checks option in strcspn 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 +#include +#include + +int main(int argc, char **argv) { + size_t size = 100; + char fill = 'o'; + char *s1 = (char*)malloc(size); + char *s2 = (char*)malloc(size); + memset(s1, fill, size); + s1[0] = 'z'; + memset(s2, fill, size); + s2[size-1] = '\0'; + size_t r = strcspn(s1, s2); + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: READ of size 101 + assert(r == 1); + free(s1); + free(s2); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strpbrk-1.c b/compiler-rt/test/asan/TestCases/strpbrk-1.c new file mode 100644 index 000000000000..65d79aa79dfd --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strpbrk-1.c @@ -0,0 +1,19 @@ +// Test string s1 overflow in strpbrk function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strpbrk asan option +// RUN: ASAN_OPTIONS=intercept_strpbrk=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + char *r; + char s2[] = "ab"; + char s1[] = {'c', 'd'}; + char s3[] = "a"; + r = strpbrk(s1, s2); + // CHECK:'s{{[1|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r <= s3); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strpbrk-2.c b/compiler-rt/test/asan/TestCases/strpbrk-2.c new file mode 100644 index 000000000000..556c8da6810f --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strpbrk-2.c @@ -0,0 +1,19 @@ +// Test stopset overflow in strpbrk function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strpbrk asan option +// RUN: ASAN_OPTIONS=intercept_strpbrk=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + char *r; + char s1[] = "a"; + char s2[] = {'b', 'c'}; + char s3 = 0; + r = strpbrk(s1, s2); + // CHECK:'s{{[2|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == (r ? s1 : 0)); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strpbrk_strict.c b/compiler-rt/test/asan/TestCases/strpbrk_strict.c new file mode 100644 index 000000000000..1bf48eccba43 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strpbrk_strict.c @@ -0,0 +1,25 @@ +// Test strict_string_checks option in strpbrk 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 +#include +#include + +int main(int argc, char **argv) { + size_t size = 100; + char fill = 'o'; + char *s1 = (char*)malloc(size); + char *s2 = (char*)malloc(2); + memset(s1, fill, size); + s2[0] = fill; + s2[1]='\0'; + char* r = strpbrk(s1, s2); + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: READ of size 101 + assert(r == s1); + free(s1); + free(s2); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strspn-1.c b/compiler-rt/test/asan/TestCases/strspn-1.c new file mode 100644 index 000000000000..8672b082c58d --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strspn-1.c @@ -0,0 +1,19 @@ +// Test string s1 overflow in strspn function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strspn asan option +// RUN: ASAN_OPTIONS=intercept_strspn=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s2[] = "ab"; + char s1[] = {'a', 'a'}; + char s3 = 0; + r = strspn(s1, s2); + // CHECK:'s{{[1|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r >= sizeof(s1)); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strspn-2.c b/compiler-rt/test/asan/TestCases/strspn-2.c new file mode 100644 index 000000000000..dbd7b7872d80 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strspn-2.c @@ -0,0 +1,19 @@ +// Test stopset overflow in strspn function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strspn asan option +// RUN: ASAN_OPTIONS=intercept_strspn=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s1[] = "cc"; + char s2[] = {'a', 'b'}; + char s3 = 0; + r = strspn(s1, s2); + // CHECK:'s{{[2|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == 0); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strspn_strict.c b/compiler-rt/test/asan/TestCases/strspn_strict.c new file mode 100644 index 000000000000..d7ab63ccb273 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strspn_strict.c @@ -0,0 +1,25 @@ +// Test strict_str`ing_checks option in strspn 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 +#include +#include + +int main(int argc, char **argv) { + size_t size = 100; + char fill = 'o'; + char *s1 = (char*)malloc(size); + char *s2 = (char*)malloc(2); + memset(s1, fill, size); + s1[0] = s2[0] = 'z'; + s2[1] = '\0'; + size_t r = strspn(s1, s2); + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: READ of size 101 + assert(r == 1); + free(s1); + free(s2); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strstr-1.c b/compiler-rt/test/asan/TestCases/strstr-1.c new file mode 100644 index 000000000000..5cbd5c353509 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strstr-1.c @@ -0,0 +1,19 @@ +// Test haystack overflow in strstr function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strstr asan option +// RUN: ASAN_OPTIONS=intercept_strstr=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + char *r = 0; + char s2[] = "c"; + char s1[] = {'a', 'b'}; + char s3 = 0; + r = strstr(s1, s2); + // CHECK:'s{{[1|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == 0); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strstr-2.c b/compiler-rt/test/asan/TestCases/strstr-2.c new file mode 100644 index 000000000000..1ee36de3157a --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strstr-2.c @@ -0,0 +1,19 @@ +// Test needle overflow in strstr function +// RUN: %clang_asan %s -o %t && ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +// Test intercept_strstr asan option +// RUN: ASAN_OPTIONS=intercept_strstr=false %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + char *r = 0; + char s1[] = "ab"; + char s2[] = {'c'}; + char s3 = 0; + r = strstr(s1, s2); + // CHECK:'s{{[2|3]}}' <== Memory access at offset {{[0-9]+ .*}}flows this variable + assert(r == 0); + return 0; +} diff --git a/compiler-rt/test/asan/TestCases/strstr_strict.c b/compiler-rt/test/asan/TestCases/strstr_strict.c new file mode 100644 index 000000000000..e2e11fe38e06 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/strstr_strict.c @@ -0,0 +1,25 @@ +// Test strict_string_checks option in strstr 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 +#include +#include + +int main(int argc, char **argv) { + size_t size = 100; + char fill = 'o'; + char *s1 = (char*)malloc(size); + char *s2 = (char*)malloc(size); + memset(s1, fill, size); + memset(s2, fill, size); + s2[size - 1]='\0'; + char* r = strstr(s1, s2); + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: READ of size 101 + assert(r == s1); + free(s1); + free(s2); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/strcasestr.c b/compiler-rt/test/sanitizer_common/TestCases/strcasestr.c new file mode 100644 index 000000000000..4de3cac7e253 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/strcasestr.c @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +// There's no interceptor for strcasestr on Windows +// XFAIL: win32 + +#define _GNU_SOURCE +#include +#include +int main(int argc, char **argv) { + char *r = 0; + char s1[] = "aB"; + char s2[] = "b"; + r = strcasestr(s1, s2); + assert(r == s1 + 1); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/strcspn.c b/compiler-rt/test/sanitizer_common/TestCases/strcspn.c new file mode 100644 index 000000000000..066a27bbdf2c --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/strcspn.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s1[] = "ad"; + char s2[] = "cd"; + r = strcspn(s1, s2); + assert(r == 1); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/strpbrk.c b/compiler-rt/test/sanitizer_common/TestCases/strpbrk.c new file mode 100644 index 000000000000..318e3a4977f2 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/strpbrk.c @@ -0,0 +1,14 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include +#include + + +int main(int argc, char **argv) { + char *r = 0; + char s1[] = "ad"; + char s2[] = "cd"; + r = strpbrk(s1, s2); + assert(r == s1 + 1); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/strspn.c b/compiler-rt/test/sanitizer_common/TestCases/strspn.c new file mode 100644 index 000000000000..a9a24305c6f1 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/strspn.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include +#include + +int main(int argc, char **argv) { + size_t r; + char s1[] = "ab"; + char s2[] = "ac"; + r = strspn(s1, s2); + assert(r == 1); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/strstr.c b/compiler-rt/test/sanitizer_common/TestCases/strstr.c new file mode 100644 index 000000000000..2089ac7b5fcb --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/strstr.c @@ -0,0 +1,12 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include +#include +int main(int argc, char **argv) { + char *r = 0; + char s1[] = "ab"; + char s2[] = "b"; + r = strstr(s1, s2); + assert(r == s1 + 1); + return 0; +}