Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -144,7 +144,8 @@ 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)) + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) ) #ifndef COMMON_INTERCEPTOR_ON_DLOPEN #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ @@ -450,8 +451,7 @@ 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_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); } #endif @@ -577,10 +577,11 @@ return internal_strchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); char *result = REAL(strchr)(s, c); - uptr len = internal_strlen(s); - uptr n = result ? result - s + 1 : len + 1; - if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n); + if (common_flags()->intercept_strchr) { + // Keep strlen as macro argument, as macro may ignore it. + COMMON_INTERCEPTOR_READ_STRING(ctx, s, + (result ? result - s : REAL(strlen)(s)) + 1); + } return result; } #define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) @@ -609,9 +610,9 @@ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strrchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); - uptr len = internal_strlen(s); - if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1); + if (common_flags()->intercept_strchr) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); + } return REAL(strrchr)(s, c); } #define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) Index: test/asan/TestCases/strchr_strict.c =================================================================== --- test/asan/TestCases/strchr_strict.c +++ test/asan/TestCases/strchr_strict.c @@ -4,19 +4,53 @@ // RUN: %env_asan_opts=strict_string_checks=true not %run %t 2>&1 | FileCheck %s #include +#include #include #include +#if defined(_WIN32) + +#include + +static uintptr_t get_page_size() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} + +static void protect(void *addr, size_t len) { + DWORD p = 0; + VirtualProtect(addr, len, PAGE_NOACCESS, &p); +} + +#else // _WIN32 + +#include +#include + +static size_t get_page_size() { return sysconf(_SC_PAGE_SIZE); } +static void protect(void *addr, size_t len) { mprotect(addr, len, PROT_NONE); } + +#endif // _WIN32 + int main(int argc, char **argv) { - size_t size = 100; + size_t page_size = get_page_size(); + size_t size = 100 * page_size; char fill = 'o'; char *s = (char*)malloc(size); + char *p = (char *)((uintptr_t)s & (-page_size)) + 3 * page_size; + --p; memset(s, fill, size); - char c = 'o'; - char* r = strchr(s, c); + *p = 'x'; + char *r = strchr(s, 'x'); // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} - // CHECK: READ of size 101 - assert(r == s); + // CHECK: READ of size + assert(r == p); + + //strict_string_checks=false must not look beyond requested char. + protect(p + 1, page_size); + r = strchr(s, 'x'); + free(s); return 0; }