From 8ecd0e5d9f389d18653892851c6ffb2f235de4b7 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 30 Apr 2013 11:56:56 +0000 Subject: tsan: add interface functions for unaligned access, e.g. __sanitizer_unaligned_load16 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@180780 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/analyze_libtsan.sh | 4 +- lib/tsan/lit_tests/unaligned_norace.cc | 84 ++++++++++++++++++++ lib/tsan/lit_tests/unaligned_race.cc | 137 +++++++++++++++++++++++++++++++++ lib/tsan/rtl/tsan_interface.cc | 50 ++++++++++++ lib/tsan/rtl/tsan_interface.h | 7 ++ lib/tsan/rtl/tsan_rtl.cc | 21 +++++ lib/tsan/rtl/tsan_rtl.h | 2 + 7 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 lib/tsan/lit_tests/unaligned_norace.cc create mode 100644 lib/tsan/lit_tests/unaligned_race.cc diff --git a/lib/tsan/analyze_libtsan.sh b/lib/tsan/analyze_libtsan.sh index e08056107..705e4c546 100755 --- a/lib/tsan/analyze_libtsan.sh +++ b/lib/tsan/analyze_libtsan.sh @@ -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) diff --git a/lib/tsan/lit_tests/unaligned_norace.cc b/lib/tsan/lit_tests/unaligned_norace.cc new file mode 100644 index 000000000..792224b80 --- /dev/null +++ b/lib/tsan/lit_tests/unaligned_norace.cc @@ -0,0 +1,84 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include +#include +#include +#include + +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 diff --git a/lib/tsan/lit_tests/unaligned_race.cc b/lib/tsan/lit_tests/unaligned_race.cc new file mode 100644 index 000000000..f3ce9475f --- /dev/null +++ b/lib/tsan/lit_tests/unaligned_race.cc @@ -0,0 +1,137 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include +#include +#include +#include +#include + +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 +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 +static void access2(bool main, int sz1, int off2, bool rw, char *obj) { + if (off2 == 0) + access3(main, sz1, rw, obj); + else if (off2 == 1) + access3(main, sz1, rw, obj); + else if (off2 == 2) + access3(main, sz1, rw, obj); + else if (off2 == 3) + access3(main, sz1, rw, obj); + else if (off2 == 4) + access3(main, sz1, rw, obj); + else if (off2 == 5) + access3(main, sz1, rw, obj); + else if (off2 == 6) + access3(main, sz1, rw, obj); + else if (off2 == 7) + access3(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 diff --git a/lib/tsan/rtl/tsan_interface.cc b/lib/tsan/rtl/tsan_interface.cc index dd06bbe4b..efad8c192 100644 --- a/lib/tsan/rtl/tsan_interface.cc +++ b/lib/tsan/rtl/tsan_interface.cc @@ -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); } diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h index 24526615d..457fb55e0 100644 --- a/lib/tsan/rtl/tsan_interface.h +++ b/lib/tsan/rtl/tsan_interface.h @@ -41,6 +41,13 @@ void __tsan_write4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE; 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; diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index 546cc196a..1205028e3 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -462,6 +462,27 @@ void MemoryAccessImpl(ThreadState *thr, uptr addr, 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) { diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 983be1371..efd6b140e 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -641,6 +641,8 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, 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; -- cgit v1.2.1