tsan: add interface functions for unaligned access, e.g. __sanitizer_unaligned_load16

llvm-svn: 180780
This commit is contained in:
Dmitry Vyukov 2013-04-30 11:56:56 +00:00
parent d73f37bb83
commit 3f7bf08b12
7 changed files with 303 additions and 2 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;