[compiler-rt] r243595 - [asan, tsan, msan] move the memcmp interceptor from asan/tsan to sanitizer_common. This may potentially lead to more reports from msan as it now sees the reads inside memcmp. To disable, use the flag intercept_memcmp=0. Likewise, it may potentially cause new races to appear due to more strict memcmp checking (flag strict_memcmp=1)

Kostya Serebryany kcc at google.com
Wed Jul 29 16:53:09 PDT 2015


Author: kcc
Date: Wed Jul 29 18:53:08 2015
New Revision: 243595

URL: http://llvm.org/viewvc/llvm-project?rev=243595&view=rev
Log:
[asan,tsan,msan] move the memcmp interceptor from asan/tsan to sanitizer_common. This may potentially lead to more reports from msan as it now sees the reads inside memcmp. To disable, use the flag intercept_memcmp=0. Likewise, it may potentially cause new races to appear due to more strict memcmp checking (flag strict_memcmp=1)

Added:
    compiler-rt/trunk/test/msan/memcmp_test.cc
    compiler-rt/trunk/test/tsan/memcmp_race.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_flags.inc
    compiler-rt/trunk/lib/asan/asan_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/sanitizer_common/sanitizer_platform_interceptors.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc

Modified: compiler-rt/trunk/lib/asan/asan_flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_flags.inc?rev=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_flags.inc (original)
+++ compiler-rt/trunk/lib/asan/asan_flags.inc Wed Jul 29 18:53:08 2015
@@ -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 "

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=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Wed Jul 29 18:53:08 2015
@@ -363,40 +363,6 @@ INTERCEPTOR(void, __cxa_throw, void *a,
 }
 #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) {

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=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc Wed Jul 29 18:53:08 2015
@@ -362,6 +362,42 @@ INTERCEPTOR(char *, strpbrk, const char
 #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;

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=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc Wed Jul 29 18:53:08 2015
@@ -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")

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h?rev=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h Wed Jul 29 18:53:08 2015
@@ -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
 

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=243595&r1=243594&r2=243595&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Jul 29 18:53:08 2015
@@ -606,20 +606,6 @@ TSAN_INTERCEPTOR(void*, memcpy, void *ds
   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);

Added: compiler-rt/trunk/test/msan/memcmp_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/msan/memcmp_test.cc?rev=243595&view=auto
==============================================================================
--- compiler-rt/trunk/test/msan/memcmp_test.cc (added)
+++ compiler-rt/trunk/test/msan/memcmp_test.cc Wed Jul 29 18:53:08 2015
@@ -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
+}

Added: compiler-rt/trunk/test/tsan/memcmp_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/memcmp_race.cc?rev=243595&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/memcmp_race.cc (added)
+++ compiler-rt/trunk/test/tsan/memcmp_race.cc Wed Jul 29 18:53:08 2015
@@ -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





More information about the llvm-commits mailing list