forked from OSchip/llvm-project
tsan: support synchronization by means of linux aio
http://llvm-reviews.chandlerc.com/D2269 llvm-svn: 195830
This commit is contained in:
parent
3701f5465c
commit
ee882ba4a1
|
@ -93,8 +93,8 @@ int main(int argc, char *argv[]) {
|
||||||
iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
|
iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
|
||||||
iocb[1].aio_buf = (__u64)(&buf[kFortyTwo]);
|
iocb[1].aio_buf = (__u64)(&buf[kFortyTwo]);
|
||||||
iocb[1].aio_nbytes = kFortyTwo;
|
iocb[1].aio_nbytes = kFortyTwo;
|
||||||
__sanitizer_syscall_post_io_submit(1, 0, 2, &iocbp);
|
__sanitizer_syscall_pre_io_submit(0, 2, &iocbp);
|
||||||
assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
|
assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * kFortyTwo);
|
||||||
|
|
||||||
__msan_poison(buf, sizeof(buf));
|
__msan_poison(buf, sizeof(buf));
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
|
|
|
@ -25,8 +25,16 @@
|
||||||
// COMMON_SYSCALL_POST_WRITE_RANGE
|
// COMMON_SYSCALL_POST_WRITE_RANGE
|
||||||
// Called in posthook for regions that were written to by the kernel
|
// Called in posthook for regions that were written to by the kernel
|
||||||
// and are now initialized.
|
// and are now initialized.
|
||||||
|
// COMMON_SYSCALL_ACQUIRE(addr)
|
||||||
|
// Acquire memory visibility from addr.
|
||||||
|
// COMMON_SYSCALL_RELEASE(addr)
|
||||||
|
// Release memory visibility to addr.
|
||||||
// COMMON_SYSCALL_FD_CLOSE(fd)
|
// COMMON_SYSCALL_FD_CLOSE(fd)
|
||||||
// Called before closing file descriptor fd.
|
// Called before closing file descriptor fd.
|
||||||
|
// COMMON_SYSCALL_FD_ACQUIRE(fd)
|
||||||
|
// Acquire memory visibility from fd.
|
||||||
|
// COMMON_SYSCALL_FD_RELEASE(fd)
|
||||||
|
// Release memory visibility to fd.
|
||||||
// COMMON_SYSCALL_PRE_FORK()
|
// COMMON_SYSCALL_PRE_FORK()
|
||||||
// Called before fork syscall.
|
// Called before fork syscall.
|
||||||
// COMMON_SYSCALL_POST_FORK(long res)
|
// COMMON_SYSCALL_POST_FORK(long res)
|
||||||
|
@ -48,16 +56,32 @@
|
||||||
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
|
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
|
||||||
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
|
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
|
||||||
|
|
||||||
|
#ifndef COMMON_SYSCALL_ACQUIRE
|
||||||
|
# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef COMMON_SYSCALL_RELEASE
|
||||||
|
# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef COMMON_SYSCALL_FD_CLOSE
|
#ifndef COMMON_SYSCALL_FD_CLOSE
|
||||||
# define COMMON_SYSCALL_FD_CLOSE(fd)
|
# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef COMMON_SYSCALL_FD_ACQUIRE
|
||||||
|
# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef COMMON_SYSCALL_FD_RELEASE
|
||||||
|
# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef COMMON_SYSCALL_PRE_FORK
|
#ifndef COMMON_SYSCALL_PRE_FORK
|
||||||
# define COMMON_SYSCALL_PRE_FORK()
|
# define COMMON_SYSCALL_PRE_FORK() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef COMMON_SYSCALL_POST_FORK
|
#ifndef COMMON_SYSCALL_POST_FORK
|
||||||
# define COMMON_SYSCALL_POST_FORK(res)
|
# define COMMON_SYSCALL_POST_FORK(res) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
|
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
|
||||||
|
@ -1263,44 +1287,70 @@ PRE_SYSCALL(io_destroy)(long ctx) {}
|
||||||
|
|
||||||
POST_SYSCALL(io_destroy)(long res, long ctx) {}
|
POST_SYSCALL(io_destroy)(long res, long ctx) {}
|
||||||
|
|
||||||
PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, void *events,
|
PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr,
|
||||||
void *timeout) {
|
__sanitizer_io_event *ioevpp, void *timeout) {
|
||||||
if (timeout) PRE_READ(timeout, struct_timespec_sz);
|
if (timeout) PRE_READ(timeout, struct_timespec_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
|
POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
|
||||||
void *events, void *timeout) {
|
__sanitizer_io_event *ioevpp, void *timeout) {
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
if (events) POST_WRITE(events, res * struct_io_event_sz);
|
if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp));
|
||||||
if (timeout) POST_WRITE(timeout, struct_timespec_sz);
|
if (timeout) POST_WRITE(timeout, struct_timespec_sz);
|
||||||
}
|
}
|
||||||
|
for (long i = 0; i < res; i++) {
|
||||||
|
// We synchronize io_submit -> io_getevents/io_cancel using the
|
||||||
|
// user-provided data context. Data is not necessary a pointer, it can be
|
||||||
|
// an int, 0 or whatever; acquire/release will correctly handle this.
|
||||||
|
// This scheme can lead to false negatives, e.g. when all operations
|
||||||
|
// synchronize on 0. But there does not seem to be a better solution
|
||||||
|
// (except wrapping all operations in own context, which is unreliable).
|
||||||
|
// We can not reliably extract fildes in io_getevents.
|
||||||
|
COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
|
PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
|
||||||
for (long i = 0; i < nr; ++i) {
|
for (long i = 0; i < nr; ++i) {
|
||||||
if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pwrite && iocbpp[i]->aio_buf &&
|
uptr op = iocbpp[i]->aio_lio_opcode;
|
||||||
iocbpp[i]->aio_nbytes)
|
void *data = (void*)iocbpp[i]->aio_data;
|
||||||
PRE_READ((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
|
void *buf = (void*)iocbpp[i]->aio_buf;
|
||||||
|
uptr len = (uptr)iocbpp[i]->aio_nbytes;
|
||||||
|
if (op == iocb_cmd_pwrite && buf && len) {
|
||||||
|
PRE_READ(buf, len);
|
||||||
|
} else if (op == iocb_cmd_pread && buf && len) {
|
||||||
|
POST_WRITE(buf, len);
|
||||||
|
} else if (op == iocb_cmd_pwritev) {
|
||||||
|
__sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
|
||||||
|
for (uptr v = 0; v < len; v++)
|
||||||
|
PRE_READ(iovec[i].iov_base, iovec[i].iov_len);
|
||||||
|
} else if (op == iocb_cmd_preadv) {
|
||||||
|
__sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
|
||||||
|
for (uptr v = 0; v < len; v++)
|
||||||
|
POST_WRITE(iovec[i].iov_base, iovec[i].iov_len);
|
||||||
|
}
|
||||||
|
// See comment in io_getevents.
|
||||||
|
COMMON_SYSCALL_RELEASE(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
|
POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
|
||||||
__sanitizer_iocb **iocbpp) {
|
__sanitizer_iocb **iocbpp) {}
|
||||||
if (res > 0 && iocbpp) {
|
|
||||||
for (long i = 0; i < res; ++i) {
|
PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb,
|
||||||
if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pread && iocbpp[i]->aio_buf &&
|
__sanitizer_io_event *result) {
|
||||||
iocbpp[i]->aio_nbytes)
|
|
||||||
POST_WRITE((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *result) {}
|
POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb,
|
||||||
|
__sanitizer_io_event *result) {
|
||||||
POST_SYSCALL(io_cancel)(long res, long ctx_id, void *iocb, void *result) {
|
if (res == 0) {
|
||||||
if (res >= 0) {
|
if (result) {
|
||||||
if (iocb) POST_WRITE(iocb, sizeof(__sanitizer_iocb));
|
// See comment in io_getevents.
|
||||||
if (result) POST_WRITE(result, struct_io_event_sz);
|
COMMON_SYSCALL_ACQUIRE((void*)result->data);
|
||||||
|
POST_WRITE(result, sizeof(*result));
|
||||||
|
}
|
||||||
|
if (iocb)
|
||||||
|
POST_WRITE(iocb, sizeof(*iocb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,11 @@ COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));
|
||||||
COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
|
COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
COMPILER_CHECK(struct_io_event_sz == sizeof(struct io_event));
|
COMPILER_CHECK(sizeof(__sanitizer_io_event) == sizeof(struct io_event));
|
||||||
|
CHECK_SIZE_AND_OFFSET(io_event, data);
|
||||||
|
CHECK_SIZE_AND_OFFSET(io_event, obj);
|
||||||
|
CHECK_SIZE_AND_OFFSET(io_event, res);
|
||||||
|
CHECK_SIZE_AND_OFFSET(io_event, res2);
|
||||||
|
|
||||||
#if !SANITIZER_ANDROID
|
#if !SANITIZER_ANDROID
|
||||||
COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
|
COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
|
||||||
|
|
|
@ -70,7 +70,6 @@ namespace __sanitizer {
|
||||||
const unsigned struct_kernel_stat_sz = 144;
|
const unsigned struct_kernel_stat_sz = 144;
|
||||||
const unsigned struct_kernel_stat64_sz = 104;
|
const unsigned struct_kernel_stat64_sz = 104;
|
||||||
#endif
|
#endif
|
||||||
const unsigned struct_io_event_sz = 32;
|
|
||||||
struct __sanitizer_perf_event_attr {
|
struct __sanitizer_perf_event_attr {
|
||||||
unsigned type;
|
unsigned type;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
@ -109,8 +108,17 @@ namespace __sanitizer {
|
||||||
u64 aio_reserved3;
|
u64 aio_reserved3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __sanitizer_io_event {
|
||||||
|
u64 data;
|
||||||
|
u64 obj;
|
||||||
|
u64 res;
|
||||||
|
u64 res2;
|
||||||
|
};
|
||||||
|
|
||||||
const unsigned iocb_cmd_pread = 0;
|
const unsigned iocb_cmd_pread = 0;
|
||||||
const unsigned iocb_cmd_pwrite = 1;
|
const unsigned iocb_cmd_pwrite = 1;
|
||||||
|
const unsigned iocb_cmd_preadv = 7;
|
||||||
|
const unsigned iocb_cmd_pwritev = 8;
|
||||||
|
|
||||||
struct __sanitizer___sysctl_args {
|
struct __sanitizer___sysctl_args {
|
||||||
int *name;
|
int *name;
|
||||||
|
|
|
@ -1927,10 +1927,33 @@ static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
|
||||||
MemoryAccessRange(thr, pc, p, s, write);
|
MemoryAccessRange(thr, pc, p, s, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syscall_acquire(uptr pc, uptr addr) {
|
||||||
|
TSAN_SYSCALL();
|
||||||
|
Acquire(thr, pc, addr);
|
||||||
|
Printf("syscall_acquire(%p)\n", addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscall_release(uptr pc, uptr addr) {
|
||||||
|
TSAN_SYSCALL();
|
||||||
|
Printf("syscall_release(%p)\n", addr);
|
||||||
|
Release(thr, pc, addr);
|
||||||
|
}
|
||||||
|
|
||||||
static void syscall_fd_close(uptr pc, int fd) {
|
static void syscall_fd_close(uptr pc, int fd) {
|
||||||
TSAN_SYSCALL();
|
TSAN_SYSCALL();
|
||||||
if (fd >= 0)
|
FdClose(thr, pc, fd);
|
||||||
FdClose(thr, pc, fd);
|
}
|
||||||
|
|
||||||
|
static USED void syscall_fd_acquire(uptr pc, int fd) {
|
||||||
|
TSAN_SYSCALL();
|
||||||
|
FdAcquire(thr, pc, fd);
|
||||||
|
Printf("syscall_fd_acquire(%p)\n", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static USED void syscall_fd_release(uptr pc, int fd) {
|
||||||
|
TSAN_SYSCALL();
|
||||||
|
Printf("syscall_fd_release(%p)\n", fd);
|
||||||
|
FdRelease(thr, pc, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscall_pre_fork(uptr pc) {
|
static void syscall_pre_fork(uptr pc) {
|
||||||
|
@ -1949,23 +1972,40 @@ static void syscall_post_fork(uptr pc, int res) {
|
||||||
|
|
||||||
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
|
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
|
||||||
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
|
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
|
||||||
|
|
||||||
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
|
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
|
||||||
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
|
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
|
||||||
|
|
||||||
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
|
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
|
||||||
do { \
|
do { \
|
||||||
(void)(p); \
|
(void)(p); \
|
||||||
(void)(s); \
|
(void)(s); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
|
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
|
||||||
do { \
|
do { \
|
||||||
(void)(p); \
|
(void)(p); \
|
||||||
(void)(s); \
|
(void)(s); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
#define COMMON_SYSCALL_ACQUIRE(addr) \
|
||||||
|
syscall_acquire(GET_CALLER_PC(), (uptr)(addr))
|
||||||
|
|
||||||
|
#define COMMON_SYSCALL_RELEASE(addr) \
|
||||||
|
syscall_release(GET_CALLER_PC(), (uptr)(addr))
|
||||||
|
|
||||||
#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
|
#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
|
||||||
|
|
||||||
|
#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd)
|
||||||
|
|
||||||
|
#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd)
|
||||||
|
|
||||||
#define COMMON_SYSCALL_PRE_FORK() \
|
#define COMMON_SYSCALL_PRE_FORK() \
|
||||||
syscall_pre_fork(GET_CALLER_PC())
|
syscall_pre_fork(GET_CALLER_PC())
|
||||||
|
|
||||||
#define COMMON_SYSCALL_POST_FORK(res) \
|
#define COMMON_SYSCALL_POST_FORK(res) \
|
||||||
syscall_post_fork(GET_CALLER_PC(), res)
|
syscall_post_fork(GET_CALLER_PC(), res)
|
||||||
|
|
||||||
#include "sanitizer_common/sanitizer_common_syscalls.inc"
|
#include "sanitizer_common/sanitizer_common_syscalls.inc"
|
||||||
|
|
||||||
namespace __tsan {
|
namespace __tsan {
|
||||||
|
|
Loading…
Reference in New Issue