summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2013-10-15 11:31:51 +0000
committerDmitry Vyukov <dvyukov@google.com>2013-10-15 11:31:51 +0000
commit0f7a2acb3326a5900d1a1339ebf959b14b372e0d (patch)
tree5a77aa186006c7764be30822c4ed0dc2d7d47d4c
parent97f4e082ff0f6aa13ef9e30cd611c1e9246ca7a6 (diff)
downloadcompiler-rt-0f7a2acb3326a5900d1a1339ebf959b14b372e0d.tar.gz
compiler-rt-0f7a2acb3326a5900d1a1339ebf959b14b372e0d.tar.bz2
compiler-rt-0f7a2acb3326a5900d1a1339ebf959b14b372e0d.tar.xz
tsan: implement internal syscall-based versions of sigaction/sigprocmask
use them in stoptheworld fixes applications that intercept sigaction/sigprocmask git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@192686 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/sanitizer_common/sanitizer_common_syscalls.inc5
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc25
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h22
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc32
4 files changed, 64 insertions, 20 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 942ffc4c..eef79864 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -37,6 +37,7 @@
#if SANITIZER_LINUX
#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
#define PRE_SYSCALL(name) \
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
@@ -103,10 +104,6 @@ struct sanitizer_kernel_sockaddr {
char sa_data[14];
};
-// Real sigset size is always passed as a syscall argument.
-// Declare it "void" to catch sizeof(kernel_sigset_t).
-typedef void kernel_sigset_t;
-
static void kernel_write_iovec(const __sanitizer_iovec *iovec,
SIZE_T iovlen, SIZE_T maxlen) {
for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index c1390ff1..9b5620d6 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -602,6 +602,31 @@ uptr internal_sigaltstack(const struct sigaltstack *ss,
return internal_syscall(__NR_sigaltstack, ss, oss);
}
+uptr internal_sigaction(int signum, const kernel_sigaction_t *act,
+ struct kernel_sigaction_t *oldact) {
+ return internal_syscall(__NR_rt_sigaction, signum, act, oldact,
+ sizeof(kernel_sigset_t));
+}
+
+uptr internal_sigprocmask(int how, kernel_sigset_t *set,
+ kernel_sigset_t *oldset) {
+ return internal_syscall(__NR_rt_sigprocmask, (uptr)how, &set->sig[0],
+ &oldset->sig[0], sizeof(kernel_sigset_t));
+}
+
+void internal_sigfillset(kernel_sigset_t *set) {
+ internal_memset(set, 0xff, sizeof(*set));
+}
+
+void internal_sigdelset(kernel_sigset_t *set, int signum) {
+ signum -= 1;
+ CHECK_GE(signum, 0);
+ CHECK_LT(signum, sizeof(*set) * 8);
+ const uptr idx = signum / (sizeof(set->sig[0]) * 8);
+ const uptr bit = signum % (sizeof(set->sig[0]) * 8);
+ set->sig[idx] &= ~(1 << bit);
+}
+
// ThreadLister implementation.
ThreadLister::ThreadLister(int pid)
: pid_(pid),
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 08b06e57..5a642c88 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -20,17 +20,39 @@
struct link_map; // Opaque type returned by dlopen().
struct sigaltstack;
+typedef struct siginfo siginfo_t;
namespace __sanitizer {
// Dirent structure for getdents(). Note that this structure is different from
// the one in <dirent.h>, which is used by readdir().
struct linux_dirent;
+struct kernel_sigset_t {
+ u8 sig[FIRST_32_SECOND_64(16, 8)];
+};
+
+struct kernel_sigaction_t {
+ union {
+ void (*sigaction)(int signo, siginfo_t *info, void *ctx);
+ void (*handler)(int signo);
+ };
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ kernel_sigset_t sa_mask;
+};
+
// Syscall wrappers.
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);
+uptr internal_sigaction(int signum, const kernel_sigaction_t *act,
+ kernel_sigaction_t *oldact);
+uptr internal_sigprocmask(int how, kernel_sigset_t *set,
+ kernel_sigset_t *oldset);
+void internal_sigfillset(kernel_sigset_t *set);
+void internal_sigdelset(kernel_sigset_t *set, int signum);
+
#ifdef __x86_64__
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 163bd45a..492da16c 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -252,12 +252,12 @@ static int TracerThread(void* argument) {
// the mask we inherited from the caller thread.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- struct sigaction new_sigaction;
+ kernel_sigaction_t new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_sigaction = TracerThreadSignalHandler;
+ new_sigaction.sigaction = TracerThreadSignalHandler;
new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+ internal_sigfillset(&new_sigaction.sa_mask);
+ internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
}
int exit_code = 0;
@@ -307,9 +307,9 @@ NOINLINE static void WipeStack() {
// We have a limitation on the stack frame size, so some stuff had to be moved
// into globals.
-static sigset_t blocked_sigset;
-static sigset_t old_sigset;
-static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
+static kernel_sigset_t blocked_sigset;
+static kernel_sigset_t old_sigset;
+static kernel_sigaction_t old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
class StopTheWorldScope {
public:
@@ -323,21 +323,21 @@ class StopTheWorldScope {
// We cannot allow user-defined handlers to run while the ThreadSuspender
// thread is active, because they could conceivably call some libc functions
// which modify errno (which is shared between the two threads).
- sigfillset(&blocked_sigset);
+ internal_sigfillset(&blocked_sigset);
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
// Remove the signal from the set of blocked signals.
- sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
+ internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
// Install the default handler.
- struct sigaction new_sigaction;
+ kernel_sigaction_t new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_handler = SIG_DFL;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction,
+ new_sigaction.handler = SIG_DFL;
+ internal_sigfillset(&new_sigaction.sa_mask);
+ internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction,
&old_sigactions[signal_index]);
}
int sigprocmask_status =
- sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+ internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
// Make this process dumpable. Processes that are not dumpable cannot be
// attached to.
@@ -355,10 +355,10 @@ class StopTheWorldScope {
// Restore the signal handlers.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- sigaction(kUnblockedSignals[signal_index],
+ internal_sigaction(kUnblockedSignals[signal_index],
&old_sigactions[signal_index], NULL);
}
- sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
+ internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
private: