[compiler-rt] r180780 - tsan: add interface functions for unaligned access, e.g. __sanitizer_unaligned_load16

Dmitry Vyukov dvyukov at google.com
Tue Apr 30 04:56:56 PDT 2013


Author: dvyukov
Date: Tue Apr 30 06:56:56 2013
New Revision: 180780

URL: http://llvm.org/viewvc/llvm-project?rev=180780&view=rev
Log:
tsan: add interface functions for unaligned access, e.g. __sanitizer_unaligned_load16

Added:
    compiler-rt/trunk/lib/tsan/lit_tests/unaligned_norace.cc
    compiler-rt/trunk/lib/tsan/lit_tests/unaligned_race.cc
Modified:
    compiler-rt/trunk/lib/tsan/analyze_libtsan.sh
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h

Modified: compiler-rt/trunk/lib/tsan/analyze_libtsan.sh
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/analyze_libtsan.sh?rev=180780&r1=180779&r2=180780&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/analyze_libtsan.sh (original)
+++ compiler-rt/trunk/lib/tsan/analyze_libtsan.sh Tue Apr 30 06:56:56 2013
@@ -4,7 +4,7 @@ set -e
 set -u
 
 get_asm() {
-  grep tsan_$1.: -A 10000 libtsan.objdump | \
+  grep __tsan_$1.: -A 10000 libtsan.objdump | \
     awk "/[^:]$/ {print;} />:/ {c++; if (c == 2) {exit}}"
 }
 
@@ -27,7 +27,7 @@ for f in $list; do
   file=asm_$f.s
   get_asm $f > $file
   tot=$(wc -l < $file)
-  size=$(grep $f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
+  size=$(grep __tsan_$f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
   rsp=$(grep '(%rsp)' $file | wc -l)
   push=$(grep 'push' $file | wc -l)
   pop=$(grep 'pop' $file | wc -l)

Added: compiler-rt/trunk/lib/tsan/lit_tests/unaligned_norace.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/unaligned_norace.cc?rev=180780&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/unaligned_norace.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/unaligned_norace.cc Tue Apr 30 06:56:56 2013
@@ -0,0 +1,84 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+uint64_t objs[8*3*3*2][3];
+
+extern "C" {
+uint16_t __tsan_unaligned_read2(void *addr);
+uint32_t __tsan_unaligned_read4(void *addr);
+uint64_t __tsan_unaligned_read8(void *addr);
+void __tsan_unaligned_write2(void *addr, uint16_t v);
+void __tsan_unaligned_write4(void *addr, uint32_t v);
+void __tsan_unaligned_write8(void *addr, uint64_t v);
+}
+
+static void access(char *p, int sz, int rw) {
+  if (rw) {
+    switch (sz) {
+    case 0: __tsan_unaligned_write2(p, 0); break;
+    case 1: __tsan_unaligned_write4(p, 0); break;
+    case 2: __tsan_unaligned_write8(p, 0); break;
+    default: exit(1);
+    }
+  } else {
+    switch (sz) {
+    case 0: __tsan_unaligned_read2(p); break;
+    case 1: __tsan_unaligned_read4(p); break;
+    case 2: __tsan_unaligned_read8(p); break;
+    default: exit(1);
+    }
+  }
+}
+
+static int accesssize(int sz) {
+  switch (sz) {
+  case 0: return 2;
+  case 1: return 4;
+  case 2: return 8;
+  }
+  exit(1);
+}
+
+void Test(bool main) {
+  uint64_t *obj = objs[0];
+  for (int off = 0; off < 8; off++) {
+    for (int sz1 = 0; sz1 < 3; sz1++) {
+      for (int sz2 = 0; sz2 < 3; sz2++) {
+        for (int rw = 0; rw < 2; rw++) {
+          char *p = (char*)obj + off;
+          if (main) {
+            // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+            //        main, off, sz1, sz2, rw, p);
+            access(p, sz1, true);
+          } else {
+            p += accesssize(sz1);
+            // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+            //        main, off, sz1, sz2, rw, p);
+            access(p, sz2, rw);
+          }
+          obj += 3;
+        }
+      }
+    }
+  }
+}
+
+void *Thread(void *p) {
+  (void)p;
+  Test(false);
+  return 0;
+}
+
+int main() {
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  Test(true);
+  pthread_join(th, 0);
+  printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: OK

Added: compiler-rt/trunk/lib/tsan/lit_tests/unaligned_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/unaligned_race.cc?rev=180780&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/unaligned_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/unaligned_race.cc Tue Apr 30 06:56:56 2013
@@ -0,0 +1,137 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+uint64_t objs[8*2*(2 + 4 + 8)][2];
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(void *addr);
+uint32_t __sanitizer_unaligned_load32(void *addr);
+uint64_t __sanitizer_unaligned_load64(void *addr);
+void __sanitizer_unaligned_store16(void *addr, uint16_t v);
+void __sanitizer_unaligned_store32(void *addr, uint32_t v);
+void __sanitizer_unaligned_store64(void *addr, uint64_t v);
+}
+
+// All this mess is to generate unique stack for each race,
+// otherwise tsan will suppress similar stacks.
+
+static void access(char *p, int sz, int rw) {
+  if (rw) {
+    switch (sz) {
+    case 0: __sanitizer_unaligned_store16(p, 0); break;
+    case 1: __sanitizer_unaligned_store32(p, 0); break;
+    case 2: __sanitizer_unaligned_store64(p, 0); break;
+    default: exit(1);
+    }
+  } else {
+    switch (sz) {
+    case 0: __sanitizer_unaligned_load16(p); break;
+    case 1: __sanitizer_unaligned_load32(p); break;
+    case 2: __sanitizer_unaligned_load64(p); break;
+    default: exit(1);
+    }
+  }
+}
+
+static int accesssize(int sz) {
+  switch (sz) {
+  case 0: return 2;
+  case 1: return 4;
+  case 2: return 8;
+  }
+  exit(1);
+}
+
+template<int off, int off2>
+static void access3(bool main, int sz1, bool rw, char *p) {
+  p += off;
+  if (main) {
+    access(p, sz1, true);
+  } else {
+    p += off2;
+    if (rw) {
+      *p = 42;
+    } else {
+       if (*p == 42)
+         printf("bingo!\n");
+    }
+  }
+}
+
+template<int off>
+static void access2(bool main, int sz1, int off2, bool rw, char *obj) {
+  if (off2 == 0)
+    access3<off, 0>(main, sz1, rw, obj);
+  else if (off2 == 1)
+    access3<off, 1>(main, sz1, rw, obj);
+  else if (off2 == 2)
+    access3<off, 2>(main, sz1, rw, obj);
+  else if (off2 == 3)
+    access3<off, 3>(main, sz1, rw, obj);
+  else if (off2 == 4)
+    access3<off, 4>(main, sz1, rw, obj);
+  else if (off2 == 5)
+    access3<off, 5>(main, sz1, rw, obj);
+  else if (off2 == 6)
+    access3<off, 6>(main, sz1, rw, obj);
+  else if (off2 == 7)
+    access3<off, 7>(main, sz1, rw, obj);
+}
+
+static void access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
+  if (off == 0)
+    access2<0>(main, sz1, off2, rw, obj);
+  else if (off == 1)
+    access2<1>(main, sz1, off2, rw, obj);
+  else if (off == 2)
+    access2<2>(main, sz1, off2, rw, obj);
+  else if (off == 3)
+    access2<3>(main, sz1, off2, rw, obj);
+  else if (off == 4)
+    access2<4>(main, sz1, off2, rw, obj);
+  else if (off == 5)
+    access2<5>(main, sz1, off2, rw, obj);
+  else if (off == 6)
+    access2<6>(main, sz1, off2, rw, obj);
+  else if (off == 7)
+    access2<7>(main, sz1, off2, rw, obj);
+}
+
+void Test(bool main) {
+  uint64_t *obj = objs[0];
+  for (int off = 0; off < 8; off++) {
+    for (int sz1 = 0; sz1 < 3; sz1++) {
+      for (int off2 = 0; off2 < accesssize(sz1); off2++) {
+        for (int rw = 0; rw < 2; rw++) {
+          printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
+                 main, off, sz1, off2, rw, obj);
+          access1(main, off, sz1, off2, rw, (char*)obj);
+          obj += 2;
+        }
+      }
+    }
+  }
+}
+
+void *Thread(void *p) {
+  (void)p;
+  sleep(1);
+  Test(false);
+  return 0;
+}
+
+int main() {
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  Test(true);
+  pthread_join(th, 0);
+  printf("OK\n");
+}
+
+// WARNING: ThreadSanitizer: data race
+// CHECK: ThreadSanitizer: reported 224 warnings
+// CHECK: OK

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc?rev=180780&r1=180779&r2=180780&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface.cc Tue Apr 30 06:56:56 2013
@@ -14,11 +14,16 @@
 #include "tsan_interface.h"
 #include "tsan_interface_ann.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 #define CALLERPC ((uptr)__builtin_return_address(0))
 
 using namespace __tsan;  // NOLINT
 
+typedef u16 uint16_t;
+typedef u32 uint32_t;
+typedef u64 uint64_t;
+
 void __tsan_init() {
   Initialize(cur_thread());
 }
@@ -33,6 +38,51 @@ void __tsan_write16(void *addr) {
   MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
+u16 __tsan_unaligned_read2(void *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false);
+  return *(u16*)addr;
+}
+
+u32 __tsan_unaligned_read4(void *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false);
+  return *(u32*)addr;
+}
+
+u64 __tsan_unaligned_read8(void *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false);
+  return *(u64*)addr;
+}
+
+void __tsan_unaligned_write2(void *addr, u16 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false);
+  *(u16*)addr = v;
+}
+
+void __tsan_unaligned_write4(void *addr, u32 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false);
+  *(u32*)addr = v;
+}
+
+void __tsan_unaligned_write8(void *addr, u64 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false);
+  *(u64*)addr = v;
+}
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(void *addr)
+    ALIAS("__tsan_unaligned_read2") SANITIZER_INTERFACE_ATTRIBUTE;
+uint32_t __sanitizer_unaligned_load32(void *addr)
+    ALIAS("__tsan_unaligned_read4") SANITIZER_INTERFACE_ATTRIBUTE;
+uint64_t __sanitizer_unaligned_load64(void *addr)
+    ALIAS("__tsan_unaligned_read8") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store16(void *addr, uint16_t v)
+    ALIAS("__tsan_unaligned_write2") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store32(void *addr, uint32_t v)
+    ALIAS("__tsan_unaligned_write4") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store64(void *addr, uint64_t v)
+    ALIAS("__tsan_unaligned_write8") SANITIZER_INTERFACE_ATTRIBUTE;
+}
+
 void __tsan_acquire(void *addr) {
   Acquire(cur_thread(), CALLERPC, (uptr)addr);
 }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h?rev=180780&r1=180779&r2=180780&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h Tue Apr 30 06:56:56 2013
@@ -41,6 +41,13 @@ void __tsan_write4(void *addr) SANITIZER
 void __tsan_write8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_write16(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 
+u16 __tsan_unaligned_read2(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+u32 __tsan_unaligned_read4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+u64 __tsan_unaligned_read8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write2(void *addr, u16 v) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write4(void *addr, u32 v) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write8(void *addr, u64 v) SANITIZER_INTERFACE_ATTRIBUTE;
+
 void __tsan_vptr_read(void **vptr_p) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_vptr_update(void **vptr_p, void *new_val)
     SANITIZER_INTERFACE_ATTRIBUTE;

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=180780&r1=180779&r2=180780&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Tue Apr 30 06:56:56 2013
@@ -462,6 +462,27 @@ void MemoryAccessImpl(ThreadState *thr,
   return;
 }
 
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+    int size, bool kAccessIsWrite, bool kIsAtomic) {
+  while (size) {
+    int size1 = 1;
+    int kAccessSizeLog = kSizeLog1;
+    if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
+      size1 = 8;
+      kAccessSizeLog = kSizeLog8;
+    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
+      size1 = 4;
+      kAccessSizeLog = kSizeLog4;
+    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
+      size1 = 2;
+      kAccessSizeLog = kSizeLog2;
+    }
+    MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
+    addr += size1;
+    size -= size1;
+  }
+}
+
 ALWAYS_INLINE USED
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
     int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=180780&r1=180779&r2=180780&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Tue Apr 30 06:56:56 2013
@@ -641,6 +641,8 @@ void MemoryAccessRange(ThreadState *thr,
     uptr size, bool is_write);
 void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
     uptr size, uptr step, bool is_write);
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+    int size, bool kAccessIsWrite, bool kIsAtomic);
 
 const int kSizeLog1 = 0;
 const int kSizeLog2 = 1;





More information about the llvm-commits mailing list