Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -271,6 +271,97 @@ #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 @@ INIT_STRNCMP; INIT_STRCASECMP; INIT_STRNCASECMP; + INIT_STRSTR; + INIT_STRCASESTR; + INIT_STRSPN; + INIT_STRPBRK; INIT_MEMCHR; INIT_MEMRCHR; INIT_READ; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc @@ -154,3 +154,12 @@ "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.") Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ compiler-rt/trunk/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 Index: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc @@ -659,16 +659,6 @@ 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 @@ TSAN_INTERCEPT(strrchr); TSAN_INTERCEPT(strcpy); // NOLINT TSAN_INTERCEPT(strncpy); - TSAN_INTERCEPT(strstr); TSAN_INTERCEPT(strdup); TSAN_INTERCEPT(pthread_create); Index: compiler-rt/trunk/test/asan/TestCases/strcasestr-1.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcasestr-1.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strcasestr-2.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcasestr-2.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strcasestr_strict.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcasestr_strict.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strcspn-1.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcspn-1.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strcspn-2.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcspn-2.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strcspn_strict.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strcspn_strict.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strpbrk-1.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strpbrk-1.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strpbrk-2.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strpbrk-2.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strpbrk_strict.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strpbrk_strict.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strspn-1.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strspn-1.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strspn-2.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strspn-2.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strspn_strict.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strspn_strict.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strstr-1.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strstr-1.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strstr-2.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strstr-2.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/asan/TestCases/strstr_strict.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/strstr_strict.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/sanitizer_common/TestCases/strcasestr.c =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/strcasestr.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/sanitizer_common/TestCases/strcspn.c =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/strcspn.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/sanitizer_common/TestCases/strpbrk.c =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/strpbrk.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/sanitizer_common/TestCases/strspn.c =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/strspn.c +++ compiler-rt/trunk/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; +} Index: compiler-rt/trunk/test/sanitizer_common/TestCases/strstr.c =================================================================== --- compiler-rt/trunk/test/sanitizer_common/TestCases/strstr.c +++ compiler-rt/trunk/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; +}