[nolibc] Change internal syscall API to remove reliance on libc's errno.

This change moves to a model where the error value of a system call is
potentially contained in the return value itself rather than being
implicit in errno.  The helper function internal_iserror can be used
to extract the error value from a return value.  On platforms other
than Linux/x86_64 this still uses errno, but other platforms are free
to port their error handling to this new model.

Differential Revision: http://llvm-reviews.chandlerc.com/D756

llvm-svn: 181436
This commit is contained in:
Peter Collingbourne 2013-05-08 14:43:49 +00:00
parent 4307282de6
commit 6f4be19b57
17 changed files with 309 additions and 151 deletions

View File

@ -69,8 +69,8 @@ static void MaybeOpenReportFile() {
InternalScopedBuffer<char> report_path_full(4096);
internal_snprintf(report_path_full.data(), report_path_full.size(),
"%s.%d", report_path_prefix, GetPid());
fd_t fd = OpenFile(report_path_full.data(), true);
if (fd == kInvalidFd) {
uptr openrv = OpenFile(report_path_full.data(), true);
if (internal_iserror(openrv)) {
report_fd = kStderrFd;
log_to_file = false;
Report("ERROR: Can't open file: %s\n", report_path_full.data());
@ -80,7 +80,7 @@ static void MaybeOpenReportFile() {
// We're in the child. Close the parent's log.
internal_close(report_fd);
}
report_fd = fd;
report_fd = openrv;
report_fd_pid = GetPid();
}
@ -108,8 +108,9 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
*buff_size = 0;
// The files we usually open are not seekable, so try different buffer sizes.
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
fd_t fd = OpenFile(file_name, /*write*/ false);
if (fd == kInvalidFd) return 0;
uptr openrv = OpenFile(file_name, /*write*/ false);
if (internal_iserror(openrv)) return 0;
fd_t fd = openrv;
UnmapOrDie(*buff, *buff_size);
*buff = (char*)MmapOrDie(size, __FUNCTION__);
*buff_size = size;

View File

@ -115,7 +115,7 @@ void SetPrintfAndReportCallback(void (*callback)(const char *));
// Can be used to prevent mixing error reports from different sanitizers.
extern StaticSpinMutex CommonSanitizerReportMutex;
fd_t OpenFile(const char *filename, bool write);
uptr OpenFile(const char *filename, bool write);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// The size of the mmaped region is stored in '*buff_size',

View File

@ -273,10 +273,12 @@ extern "C" void* _ReturnAddress(void);
# define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
#endif
#define HANDLE_EINTR(res, f) { \
do { \
res = (f); \
} while (res == -1 && errno == EINTR); \
#define HANDLE_EINTR(res, f) \
{ \
int rverrno; \
do { \
res = (f); \
} while (internal_iserror(res, &rverrno) && rverrno == EINTR); \
}
#endif // SANITIZER_DEFS_H

View File

@ -53,42 +53,45 @@ bool mem_is_zero(const char *mem, uptr size);
// Memory
void *internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset);
int internal_munmap(void *addr, uptr length);
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset);
uptr internal_munmap(void *addr, uptr length);
// I/O
const fd_t kInvalidFd = -1;
const fd_t kStdinFd = 0;
const fd_t kStdoutFd = 1;
const fd_t kStderrFd = 2;
int internal_close(fd_t fd);
uptr internal_close(fd_t fd);
int internal_isatty(fd_t fd);
// Use __sanitizer::OpenFile() instead.
fd_t internal_open(const char *filename, int flags);
fd_t internal_open(const char *filename, int flags, u32 mode);
uptr internal_open(const char *filename, int flags);
uptr internal_open(const char *filename, int flags, u32 mode);
uptr internal_read(fd_t fd, void *buf, uptr count);
uptr internal_write(fd_t fd, const void *buf, uptr count);
// OS
uptr internal_filesize(fd_t fd); // -1 on error.
int internal_stat(const char *path, void *buf);
int internal_lstat(const char *path, void *buf);
int internal_fstat(fd_t fd, void *buf);
int internal_dup2(int oldfd, int newfd);
uptr internal_stat(const char *path, void *buf);
uptr internal_lstat(const char *path, void *buf);
uptr internal_fstat(fd_t fd, void *buf);
uptr internal_dup2(int oldfd, int newfd);
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
int internal_unlink(const char *path);
uptr internal_unlink(const char *path);
void NORETURN internal__exit(int exitcode);
OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence);
uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
long internal_ptrace(int request, int pid, void *addr, void *data);
int internal_waitpid(int pid, int *status, int options);
int internal_getppid();
uptr internal_ptrace(int request, int pid, void *addr, void *data);
uptr internal_waitpid(int pid, int *status, int options);
uptr internal_getppid();
// Threading
int internal_sched_yield();
uptr internal_sched_yield();
// Error handling
bool internal_iserror(uptr retval, int *rverrno = 0);
} // namespace __sanitizer

View File

@ -72,46 +72,52 @@ extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
namespace __sanitizer {
#ifdef __x86_64__
#include "sanitizer_syscall_linux_x86_64.inc"
#else
#include "sanitizer_syscall_generic.inc"
#endif
// --------------- sanitizer_libc.h
void *internal_mmap(void *addr, uptr length, int prot, int flags,
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
return internal_syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
#else
return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
#endif
}
int internal_munmap(void *addr, uptr length) {
return syscall(__NR_munmap, addr, length);
uptr internal_munmap(void *addr, uptr length) {
return internal_syscall(__NR_munmap, addr, length);
}
int internal_close(fd_t fd) {
return syscall(__NR_close, fd);
uptr internal_close(fd_t fd) {
return internal_syscall(__NR_close, fd);
}
fd_t internal_open(const char *filename, int flags) {
return syscall(__NR_open, filename, flags);
uptr internal_open(const char *filename, int flags) {
return internal_syscall(__NR_open, filename, flags);
}
fd_t internal_open(const char *filename, int flags, u32 mode) {
return syscall(__NR_open, filename, flags, mode);
uptr internal_open(const char *filename, int flags, u32 mode) {
return internal_syscall(__NR_open, filename, flags, mode);
}
fd_t OpenFile(const char *filename, bool write) {
uptr OpenFile(const char *filename, bool write) {
return internal_open(filename,
write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}
uptr internal_read(fd_t fd, void *buf, uptr count) {
sptr res;
HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
return res;
}
uptr internal_write(fd_t fd, const void *buf, uptr count) {
sptr res;
HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, buf, count));
return res;
}
@ -135,34 +141,34 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
}
#endif
int internal_stat(const char *path, void *buf) {
uptr internal_stat(const char *path, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
return syscall(__NR_stat, path, buf);
return internal_syscall(__NR_stat, path, buf);
#else
struct stat64 buf64;
int res = syscall(__NR_stat64, path, &buf64);
int res = internal_syscall(__NR_stat64, path, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
}
int internal_lstat(const char *path, void *buf) {
uptr internal_lstat(const char *path, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
return syscall(__NR_lstat, path, buf);
return internal_syscall(__NR_lstat, path, buf);
#else
struct stat64 buf64;
int res = syscall(__NR_lstat64, path, &buf64);
int res = internal_syscall(__NR_lstat64, path, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
}
int internal_fstat(fd_t fd, void *buf) {
uptr internal_fstat(fd_t fd, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
return syscall(__NR_fstat, fd, buf);
return internal_syscall(__NR_fstat, fd, buf);
#else
struct stat64 buf64;
int res = syscall(__NR_fstat64, fd, &buf64);
int res = internal_syscall(__NR_fstat64, fd, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
@ -175,27 +181,32 @@ uptr internal_filesize(fd_t fd) {
return (uptr)st.st_size;
}
int internal_dup2(int oldfd, int newfd) {
return syscall(__NR_dup2, oldfd, newfd);
uptr internal_dup2(int oldfd, int newfd) {
return internal_syscall(__NR_dup2, oldfd, newfd);
}
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
return (uptr)syscall(__NR_readlink, path, buf, bufsize);
return internal_syscall(__NR_readlink, path, buf, bufsize);
}
int internal_unlink(const char *path) {
return syscall(__NR_unlink, path);
uptr internal_unlink(const char *path) {
return internal_syscall(__NR_unlink, path);
}
int internal_sched_yield() {
return syscall(__NR_sched_yield);
uptr internal_sched_yield() {
return internal_syscall(__NR_sched_yield);
}
void internal__exit(int exitcode) {
syscall(__NR_exit_group, exitcode);
internal_syscall(__NR_exit_group, exitcode);
Die(); // Unreachable.
}
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) {
return internal_syscall(__NR_execve, filename, argv, envp);
}
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
struct stat st;
@ -206,12 +217,12 @@ bool FileExists(const char *filename) {
}
uptr GetTid() {
return syscall(__NR_gettid);
return internal_syscall(__NR_gettid);
}
u64 NanoTime() {
kernel_timeval tv;
syscall(__NR_gettimeofday, &tv, 0);
internal_syscall(__NR_gettimeofday, &tv, 0);
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
@ -349,8 +360,10 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
void ReExec() {
char **argv, **envp;
GetArgsAndEnv(&argv, &envp);
execve("/proc/self/exe", argv, envp);
Printf("execve failed, errno %d\n", errno);
uptr rv = internal_execve("/proc/self/exe", argv, envp);
int rverrno;
CHECK_EQ(internal_iserror(rv, &rverrno), true);
Printf("execve failed, errno %d\n", rverrno);
Die();
}
@ -616,7 +629,7 @@ void BlockingMutex::Lock() {
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
return;
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
}
void BlockingMutex::Unlock() {
@ -624,7 +637,7 @@ void BlockingMutex::Unlock() {
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
CHECK_NE(v, MtxUnlocked);
if (v == MtxSleeping)
syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
}
void BlockingMutex::CheckLocked() {
@ -644,33 +657,37 @@ struct linux_dirent {
};
// Syscall wrappers.
long internal_ptrace(int request, int pid, void *addr, void *data) {
return syscall(__NR_ptrace, request, pid, addr, data);
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
return internal_syscall(__NR_ptrace, request, pid, addr, data);
}
int internal_waitpid(int pid, int *status, int options) {
return syscall(__NR_wait4, pid, status, options, NULL /* rusage */);
uptr internal_waitpid(int pid, int *status, int options) {
return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
}
int internal_getppid() {
return syscall(__NR_getppid);
uptr internal_getpid() {
return internal_syscall(__NR_getpid);
}
int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
return syscall(__NR_getdents, fd, dirp, count);
uptr internal_getppid() {
return internal_syscall(__NR_getppid);
}
OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence) {
return syscall(__NR_lseek, fd, offset, whence);
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
return internal_syscall(__NR_getdents, fd, dirp, count);
}
int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
return syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
return internal_syscall(__NR_lseek, fd, offset, whence);
}
int internal_sigaltstack(const struct sigaltstack *ss,
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
}
uptr internal_sigaltstack(const struct sigaltstack *ss,
struct sigaltstack *oss) {
return syscall(__NR_sigaltstack, ss, oss);
return internal_syscall(__NR_sigaltstack, ss, oss);
}
// ThreadLister implementation.
@ -684,12 +701,13 @@ ThreadLister::ThreadLister(int pid)
char task_directory_path[80];
internal_snprintf(task_directory_path, sizeof(task_directory_path),
"/proc/%d/task/", pid);
descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
if (descriptor_ < 0) {
uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
if (internal_iserror(openrv)) {
error_ = true;
Report("Can't open /proc/%d/task for reading.\n", pid);
} else {
error_ = false;
descriptor_ = openrv;
}
}
@ -729,7 +747,7 @@ bool ThreadLister::GetDirectoryEntries() {
bytes_read_ = internal_getdents(descriptor_,
(struct linux_dirent *)buffer_.data(),
buffer_.size());
if (bytes_read_ < 0) {
if (internal_iserror(bytes_read_)) {
Report("Can't read directory entries from /proc/%d/task.\n", pid_);
error_ = true;
return false;

View File

@ -24,9 +24,10 @@ namespace __sanitizer {
struct linux_dirent;
// Syscall wrappers.
int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
int internal_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
uptr internal_sigaltstack(const struct sigaltstack* ss,
struct sigaltstack* oss);
// This class reads thread IDs from /proc/<pid>/task using only syscalls.
class ThreadLister {

View File

@ -42,6 +42,8 @@
namespace __sanitizer {
#include "sanitizer_syscall_generic.inc"
// ---------------------- sanitizer_libc.h
void *internal_mmap(void *addr, size_t length, int prot, int flags,
int fd, u64 offset) {
@ -52,19 +54,19 @@ int internal_munmap(void *addr, uptr length) {
return munmap(addr, length);
}
int internal_close(fd_t fd) {
uptr internal_close(fd_t fd) {
return close(fd);
}
fd_t internal_open(const char *filename, int flags) {
uptr internal_open(const char *filename, int flags) {
return open(filename, flags);
}
fd_t internal_open(const char *filename, int flags, u32 mode) {
uptr internal_open(const char *filename, int flags, u32 mode) {
return open(filename, flags, mode);
}
fd_t OpenFile(const char *filename, bool write) {
uptr OpenFile(const char *filename, bool write) {
return internal_open(filename,
write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
}
@ -77,15 +79,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return write(fd, buf, count);
}
int internal_stat(const char *path, void *buf) {
uptr internal_stat(const char *path, void *buf) {
return stat(path, (struct stat *)buf);
}
int internal_lstat(const char *path, void *buf) {
uptr internal_lstat(const char *path, void *buf) {
return lstat(path, (struct stat *)buf);
}
int internal_fstat(fd_t fd, void *buf) {
uptr internal_fstat(fd_t fd, void *buf) {
return fstat(fd, (struct stat *)buf);
}
@ -96,7 +98,7 @@ uptr internal_filesize(fd_t fd) {
return (uptr)st.st_size;
}
int internal_dup2(int oldfd, int newfd) {
uptr internal_dup2(int oldfd, int newfd) {
return dup2(oldfd, newfd);
}
@ -104,7 +106,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
return readlink(path, buf, bufsize);
}
int internal_sched_yield() {
uptr internal_sched_yield() {
return sched_yield();
}

View File

@ -57,10 +57,11 @@ uptr GetThreadSelf() {
void *MmapOrDie(uptr size, const char *mem_type) {
size = RoundUpTo(size, GetPageSizeCached());
void *res = internal_mmap(0, size,
uptr res = internal_mmap(0, size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (res == (void*)-1) {
int reserrno;
if (internal_iserror(res, &reserrno)) {
static int recursion_count;
if (recursion_count) {
// The Report() and CHECK calls below may call mmap recursively and fail.
@ -70,17 +71,17 @@ void *MmapOrDie(uptr size, const char *mem_type) {
}
recursion_count++;
Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
SanitizerToolName, size, size, mem_type, errno);
SanitizerToolName, size, size, mem_type, reserrno);
DumpProcessMap();
CHECK("unable to mmap" && 0);
}
return res;
return (void *)res;
}
void UnmapOrDie(void *addr, uptr size) {
if (!addr || !size) return;
int res = internal_munmap(addr, size);
if (res != 0) {
uptr res = internal_munmap(addr, size);
if (internal_iserror(res)) {
Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
SanitizerToolName, size, size, addr);
CHECK("unable to unmap" && 0);
@ -89,39 +90,41 @@ void UnmapOrDie(void *addr, uptr size) {
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
uptr PageSize = GetPageSizeCached();
void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
RoundUpTo(size, PageSize),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
-1, 0);
if (p == (void*)-1)
int reserrno;
if (internal_iserror(p, &reserrno))
Report("ERROR: "
"%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
SanitizerToolName, size, size, fixed_addr, errno);
return p;
SanitizerToolName, size, size, fixed_addr, reserrno);
return (void *)p;
}
void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
uptr PageSize = GetPageSizeCached();
void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
RoundUpTo(size, PageSize),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-1, 0);
if (p == (void*)-1) {
int reserrno;
if (internal_iserror(p, &reserrno)) {
Report("ERROR:"
" %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
SanitizerToolName, size, size, fixed_addr, errno);
SanitizerToolName, size, size, fixed_addr, reserrno);
CHECK("unable to mmap" && 0);
}
return p;
return (void *)p;
}
void *Mprotect(uptr fixed_addr, uptr size) {
return internal_mmap((void*)fixed_addr, size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
-1, 0);
return (void *)internal_mmap((void*)fixed_addr, size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED |
MAP_NORESERVE, -1, 0);
}
void FlushUnneededShadowMemory(uptr addr, uptr size) {
@ -129,14 +132,15 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
}
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
fd_t fd = OpenFile(file_name, false);
CHECK_NE(fd, kInvalidFd);
uptr openrv = OpenFile(file_name, false);
CHECK(!internal_iserror(openrv));
fd_t fd = openrv;
uptr fsize = internal_filesize(fd);
CHECK_NE(fsize, (uptr)-1);
CHECK_GT(fsize, 0);
*buff_size = RoundUpTo(fsize, GetPageSizeCached());
void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
return (map == MAP_FAILED) ? 0 : map;
uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
return internal_iserror(map) ? 0 : (void *)map;
}

View File

@ -101,23 +101,26 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
// usually small.
if (suspended_threads_list_.Contains(thread_id))
return false;
if (internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL) != 0) {
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL),
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
Report("Could not attach to thread %d (errno %d).\n", thread_id, errno);
Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
return false;
} else {
if (SanitizerVerbosity > 0)
Report("Attached to thread %d.\n", thread_id);
// The thread is not guaranteed to stop before ptrace returns, so we must
// wait on it.
int waitpid_status;
uptr waitpid_status;
HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __WALL));
if (waitpid_status < 0) {
int wperrno;
if (internal_iserror(waitpid_status, &wperrno)) {
// Got a ECHILD error. I don't think this situation is possible, but it
// doesn't hurt to report it.
Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
errno);
wperrno);
internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
return false;
}
@ -129,14 +132,16 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
void ThreadSuspender::ResumeAllThreads() {
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
pid_t tid = suspended_threads_list_.GetThreadID(i);
if (internal_ptrace(PTRACE_DETACH, tid, NULL, NULL) == 0) {
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
&pterrno)) {
if (SanitizerVerbosity > 0)
Report("Detached from thread %d.\n", tid);
} else {
// Either the thread is dead, or we are already detached.
// The latter case is possible, for instance, if this function was called
// from a signal handler.
Report("Could not detach from thread %d (errno %d).\n", tid, errno);
Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
}
}
}
@ -330,9 +335,10 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
// must avoid using errno while the tracer thread is running.
// At this point, any signal will either be blocked or kill us, so waitpid
// should never return (and set errno) while the tracer thread is alive.
int waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
if (waitpid_status < 0)
Report("Waiting on the tracer thread failed (errno %d).\n", errno);
uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
int wperrno;
if (internal_iserror(waitpid_status, &wperrno))
Report("Waiting on the tracer thread failed (errno %d).\n", wperrno);
}
// Restore the dumpable flag.
if (!process_was_dumpable)
@ -358,9 +364,11 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
uptr *sp) const {
pid_t tid = GetThreadID(index);
regs_struct regs;
if (internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs) != 0) {
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
&pterrno)) {
Report("Could not get registers from thread %d (errno %d).\n",
tid, errno);
tid, pterrno);
return -1;
}
#if defined(__arm__)

View File

@ -148,7 +148,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
// First module is the binary itself.
uptr module_name_len = internal_readlink(
"/proc/self/exe", module_name.data(), module_name.size());
if (module_name_len == (uptr)-1) {
if (internal_iserror(module_name_len)) {
// We can't read /proc/self/exe for some reason, assume the name of the
// binary is unknown.
module_name_len = internal_snprintf(module_name.data(),

View File

@ -0,0 +1,24 @@
//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Generic implementations of internal_syscall and internal_iserror.
//
//===----------------------------------------------------------------------===//
#define internal_syscall syscall
bool internal_iserror(uptr retval, int *rverrno) {
if (retval == (uptr)-1) {
if (rverrno)
*rverrno = errno;
return true;
} else {
return false;
}
}

View File

@ -0,0 +1,87 @@
//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implementations of internal_syscall and internal_iserror for Linux/x86_64.
//
//===----------------------------------------------------------------------===//
static uptr internal_syscall(u64 nr) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
return retval;
}
template <typename T1>
static uptr internal_syscall(u64 nr, T1 arg1) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
"rcx", "r11");
return retval;
}
template <typename T1, typename T2>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2) : "rcx", "r11");
return retval;
}
template <typename T1, typename T2, typename T3>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11");
return retval;
}
template <typename T1, typename T2, typename T3, typename T4>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
u64 retval;
asm volatile("mov %5, %%r10;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
"rcx", "r11", "r10");
return retval;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
T5 arg5) {
u64 retval;
asm volatile("mov %5, %%r10;"
"mov %6, %%r8;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
"rcx", "r11", "r10", "r8");
return retval;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
T5 arg5, T6 arg6) {
u64 retval;
asm volatile("mov %5, %%r10;"
"mov %6, %%r8;"
"mov %7, %%r9;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
"r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9");
return retval;
}
bool internal_iserror(uptr retval, int *rverrno) {
if (retval >= (uptr)-4095) {
if (rverrno)
*rverrno = -retval;
return true;
}
return false;
}

View File

@ -29,6 +29,8 @@
namespace __sanitizer {
#include "sanitizer_syscall_generic.inc"
// --------------------- sanitizer_common.h
uptr GetPageSize() {
return 1U << 14; // FIXME: is this configurable?
@ -217,7 +219,7 @@ int internal_munmap(void *addr, uptr length) {
UNIMPLEMENTED();
}
int internal_close(fd_t fd) {
uptr internal_close(fd_t fd) {
UNIMPLEMENTED();
}
@ -233,7 +235,7 @@ fd_t internal_open(const char *filename, int flags, u32 mode) {
UNIMPLEMENTED();
}
fd_t OpenFile(const char *filename, bool write) {
uptr OpenFile(const char *filename, bool write) {
UNIMPLEMENTED();
}
@ -253,15 +255,15 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return ret;
}
int internal_stat(const char *path, void *buf) {
uptr internal_stat(const char *path, void *buf) {
UNIMPLEMENTED();
}
int internal_lstat(const char *path, void *buf) {
uptr internal_lstat(const char *path, void *buf) {
UNIMPLEMENTED();
}
int internal_fstat(fd_t fd, void *buf) {
uptr internal_fstat(fd_t fd, void *buf) {
UNIMPLEMENTED();
}
@ -269,7 +271,7 @@ uptr internal_filesize(fd_t fd) {
UNIMPLEMENTED();
}
int internal_dup2(int oldfd, int newfd) {
uptr internal_dup2(int oldfd, int newfd) {
UNIMPLEMENTED();
}
@ -277,7 +279,7 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
UNIMPLEMENTED();
}
int internal_sched_yield() {
uptr internal_sched_yield() {
Sleep(0);
return 0;
}

View File

@ -74,29 +74,31 @@ TEST(SanitizerCommon, FileOps) {
internal_snprintf(temp_filename, sizeof(temp_filename),
"/tmp/sanitizer_common.tmp.%d", uid);
#endif
fd_t fd = OpenFile(temp_filename, true);
EXPECT_NE(fd, kInvalidFd);
uptr openrv = OpenFile(temp_filename, true);
EXPECT_EQ(false, internal_iserror(openrv));
fd_t fd = openrv;
EXPECT_EQ(len1, internal_write(fd, str1, len1));
EXPECT_EQ(len2, internal_write(fd, str2, len2));
internal_close(fd);
fd = OpenFile(temp_filename, false);
EXPECT_NE(fd, kInvalidFd);
openrv = OpenFile(temp_filename, false);
EXPECT_EQ(false, internal_iserror(openrv));
fd = openrv;
uptr fsize = internal_filesize(fd);
EXPECT_EQ(len1 + len2, fsize);
#if SANITIZER_TEST_HAS_STAT_H
struct stat st1, st2, st3;
EXPECT_EQ(0, internal_stat(temp_filename, &st1));
EXPECT_EQ(0, internal_lstat(temp_filename, &st2));
EXPECT_EQ(0, internal_fstat(fd, &st3));
EXPECT_EQ(0u, internal_stat(temp_filename, &st1));
EXPECT_EQ(0u, internal_lstat(temp_filename, &st2));
EXPECT_EQ(0u, internal_fstat(fd, &st3));
EXPECT_EQ(fsize, (uptr)st3.st_size);
// Verify that internal_fstat does not write beyond the end of the supplied
// buffer.
struct stat_and_more sam;
memset(&sam, 0xAB, sizeof(sam));
EXPECT_EQ(0, internal_fstat(fd, &sam.st));
EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
EXPECT_EQ(0xAB, sam.z);
EXPECT_NE(0xAB, sam.st.st_size);
EXPECT_NE(0, sam.st.st_size);

View File

@ -178,9 +178,10 @@ static void MapRodata() {
char filename[256];
internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%u",
tmpdir, GetPid());
fd_t fd = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd == kInvalidFd)
uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
if (internal_iserror(openrv))
return;
fd_t fd = openrv;
// Fill the file with kShadowRodata.
const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
InternalScopedBuffer<u64> marker(kMarkerSize);
@ -188,9 +189,9 @@ static void MapRodata() {
*p = kShadowRodata;
internal_write(fd, marker.data(), marker.size());
// Map the file into memory.
void *page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
if (page == MAP_FAILED) {
uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
if (internal_iserror(page)) {
internal_close(fd);
internal_unlink(filename);
return;

View File

@ -121,10 +121,12 @@ static void BackgroundThread(void *arg) {
InternalScopedBuffer<char> filename(4096);
internal_snprintf(filename.data(), filename.size(), "%s.%d",
flags()->profile_memory, GetPid());
mprof_fd = OpenFile(filename.data(), true);
if (mprof_fd == kInvalidFd) {
uptr openrv = OpenFile(filename.data(), true);
if (internal_iserror(openrv)) {
Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
&filename[0]);
} else {
mprof_fd = openrv;
}
}

View File

@ -38,12 +38,13 @@ static char *ReadFile(const char *filename) {
internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
else
internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
fd_t fd = OpenFile(tmp.data(), false);
if (fd == kInvalidFd) {
uptr openrv = OpenFile(tmp.data(), false);
if (internal_iserror(openrv)) {
Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
tmp.data());
Die();
}
fd_t fd = openrv;
const uptr fsize = internal_filesize(fd);
if (fsize == (uptr)-1) {
Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",