forked from OSchip/llvm-project
tsan: add interface functions for unaligned access, e.g. __sanitizer_unaligned_load16
llvm-svn: 180780
This commit is contained in:
parent
d73f37bb83
commit
3f7bf08b12
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue