diff options
| -rw-r--r-- | compiler-rt/lib/asan/asan_flags.inc | 3 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 35 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc | 37 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_flags.inc | 6 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 16 | ||||
| -rw-r--r-- | compiler-rt/test/msan/memcmp_test.cc | 15 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/memcmp_race.cc | 42 |
8 files changed, 101 insertions, 54 deletions
diff --git a/compiler-rt/lib/asan/asan_flags.inc b/compiler-rt/lib/asan/asan_flags.inc index 40b5579da8c..7e864b559e5 100644 --- a/compiler-rt/lib/asan/asan_flags.inc +++ b/compiler-rt/lib/asan/asan_flags.inc @@ -113,9 +113,6 @@ ASAN_FLAG(bool, alloc_dealloc_mismatch, ASAN_FLAG(bool, new_delete_type_mismatch, true, "Report errors on mismatch betwen size of new and delete.") -ASAN_FLAG(bool, strict_memcmp, true, - "If true, assume that memcmp(p1, p2, n) always reads n bytes before " - "comparing p1 and p2.") ASAN_FLAG( bool, strict_init_order, false, "If true, assume that dynamic initializers can never access globals from " diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index d8b48d391ab..c1357f4ab6b 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -363,40 +363,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif -static inline int CharCmp(unsigned char c1, unsigned char c2) { - return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; -} - -INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, memcmp); - if (UNLIKELY(!asan_inited)) return internal_memcmp(a1, a2, size); - ENSURE_ASAN_INITED(); - if (flags()->replace_intrin) { - if (flags()->strict_memcmp) { - // Check the entire regions even if the first bytes of the buffers are - // different. - ASAN_READ_RANGE(ctx, a1, size); - ASAN_READ_RANGE(ctx, a2, size); - // Fallthrough to REAL(memcmp) below. - } else { - unsigned char c1 = 0, c2 = 0; - const unsigned char *s1 = (const unsigned char*)a1; - const unsigned char *s2 = (const unsigned char*)a2; - uptr i; - for (i = 0; i < size; i++) { - c1 = s1[i]; - c2 = s2[i]; - if (c1 != c2) break; - } - ASAN_READ_RANGE(ctx, s1, Min(i + 1, size)); - ASAN_READ_RANGE(ctx, s2, Min(i + 1, size)); - return CharCmp(c1, c2); - } - } - return REAL(memcmp(a1, a2, size)); -} - // memcpy is called during __asan_init() from the internals of printf(...). // We do not treat memcpy with to==from as a bug. // See http://llvm.org/bugs/show_bug.cgi?id=11763. @@ -767,7 +733,6 @@ void InitializeAsanInterceptors() { InitializeCommonInterceptors(); // Intercept mem* functions. - ASAN_INTERCEPT_FUNC(memcmp); ASAN_INTERCEPT_FUNC(memmove); ASAN_INTERCEPT_FUNC(memset); if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index c7dc47532e2..f0de440c2d5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -362,6 +362,42 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { #define INIT_STRPBRK #endif +#if SANITIZER_INTERCEPT_MEMCMP +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + if (common_flags()->intercept_memcmp) { + if (common_flags()->strict_memcmp) { + // Check the entire regions even if the first bytes of the buffers are + // different. + COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size); + COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size); + // Fallthrough to REAL(memcmp) below. + } else { + unsigned char c1 = 0, c2 = 0; + const unsigned char *s1 = (const unsigned char*)a1; + const unsigned char *s2 = (const unsigned char*)a2; + uptr i; + for (i = 0; i < size; i++) { + c1 = s1[i]; + c2 = s2[i]; + if (c1 != c2) break; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size)); + return CharCmpX(c1, c2); + } + } + return REAL(memcmp(a1, a2, size)); +} + +#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp) +#else +#define INIT_MEMCMP +#endif + #if SANITIZER_INTERCEPT_MEMCHR INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { void *ctx; @@ -5026,6 +5062,7 @@ static void InitializeCommonInterceptors() { INIT_STRSPN; INIT_STRPBRK; INIT_MEMCHR; + INIT_MEMCMP; INIT_MEMRCHR; INIT_READ; INIT_PREAD; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 79ea2fb8d3d..521be7dcc90 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -174,6 +174,12 @@ COMMON_FLAG(bool, intercept_strspn, true, COMMON_FLAG(bool, intercept_strpbrk, true, "If set, uses custom wrappers for strpbrk function " "to find more errors.") +COMMON_FLAG(bool, intercept_memcmp, true, + "If set, uses custom wrappers for memcmp function " + "to find more errors.") +COMMON_FLAG(bool, strict_memcmp, true, + "If true, assume that memcmp(p1, p2, n) always reads n bytes before " + "comparing p1 and p2.") COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer " "mappings in /proc/self/maps with " "user-readable names") diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 77cc84cd03a..52886b6ee91 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -60,6 +60,7 @@ #define SANITIZER_INTERCEPT_STRPBRK 1 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_MEMCMP 1 #define SANITIZER_INTERCEPT_MEMCHR 1 #define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index 08fd3c719ca..e4a9d23e01f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -606,20 +606,6 @@ TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) { return internal_memcpy(dst, src, size); } -TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) { - SCOPED_TSAN_INTERCEPTOR(memcmp, s1, s2, n); - int res = 0; - uptr len = 0; - for (; len < n; len++) { - if ((res = ((const unsigned char *)s1)[len] - - ((const unsigned char *)s2)[len])) - break; - } - MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false); - MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false); - return res; -} - TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) { SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n); MemoryAccessRange(thr, pc, (uptr)dst, n, true); @@ -2469,7 +2455,6 @@ void InitializeInterceptors() { // We need to setup it early, because functions like dlsym() can call it. REAL(memset) = internal_memset; REAL(memcpy) = internal_memcpy; - REAL(memcmp) = internal_memcmp; // Instruct libc malloc to consume less memory. #if !SANITIZER_FREEBSD @@ -2508,7 +2493,6 @@ void InitializeInterceptors() { TSAN_INTERCEPT(memset); TSAN_INTERCEPT(memcpy); TSAN_INTERCEPT(memmove); - TSAN_INTERCEPT(memcmp); TSAN_INTERCEPT(strchr); TSAN_INTERCEPT(strchrnul); TSAN_INTERCEPT(strrchr); diff --git a/compiler-rt/test/msan/memcmp_test.cc b/compiler-rt/test/msan/memcmp_test.cc new file mode 100644 index 00000000000..95228eb127d --- /dev/null +++ b/compiler-rt/test/msan/memcmp_test.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=intercept_memcmp=0 %run %t + +#include <string.h> +int main(int argc, char **argv) { + char a1[4]; + char a2[4]; + for (int i = 0; i < argc * 3; i++) + a2[i] = a1[i] = i; + int res = memcmp(a1, a2, 4); + return res; + // CHECK: Uninitialized bytes in __interceptor_memcmp at offset 3 + // CHECK: MemorySanitizer: use-of-uninitialized-value +} diff --git a/compiler-rt/test/tsan/memcmp_race.cc b/compiler-rt/test/tsan/memcmp_race.cc new file mode 100644 index 00000000000..465d1d02080 --- /dev/null +++ b/compiler-rt/test/tsan/memcmp_race.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s +#include "test.h" +#include <string.h> + +char *data0 = new char[10]; +char *data1 = new char[10]; +char *data2 = new char[10]; + +void *Thread1(void *x) { + static volatile int size = 1; + static volatile int sink; + sink = memcmp(data0+5, data1, size); + barrier_wait(&barrier); + return NULL; +} + +void *Thread2(void *x) { + static volatile int size = 4; + barrier_wait(&barrier); + memcpy(data0+5, data2, size); + return NULL; +} + +int main() { + barrier_init(&barrier, 2); + fprintf(stderr, "addr=%p\n", &data0[5]); + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + return 0; +} + +// CHECK: addr=[[ADDR:0x[0-9,a-f]+]] +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 1 at [[ADDR]] by thread T2: +// CHECK: #0 memcpy +// CHECK: #1 Thread2 +// CHECK: Previous read of size 1 at [[ADDR]] by thread T1: +// CHECK: #0 memcmp +// CHECK: #1 Thread1 |

