[PATCH] Run the callback on a separate stack in StopTheWorld.
Sergey Matveev
earthdok at google.com
Sat Mar 30 01:46:13 PDT 2013
- TidySigaction
- minor changes
Hi kcc, glider, samsonov,
http://llvm-reviews.chandlerc.com/D592
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D592?vs=1438&id=1452#toc
Files:
lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
Index: lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
===================================================================
--- lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
+++ lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
@@ -71,6 +71,26 @@
COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
namespace __sanitizer {
+static const uptr kTracerStackSize = 2 * 1024 * 1024;
+
+// At least in some libc implementations, sigaction() has a side-effect where
+// it copies 120 bytes from stack directly into oldact without ever touching
+// them. This happens because the size of sigset_t is larger in libc than it is
+// in kernel, and the syscall ignores the extra space. The net effect is that
+// out-of-scope stack values end up in oldact, which can cause problems
+// in LSan. To fix this we provide a wrapper that cleans up after itself.
+int TidySigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact) {
+ int res = sigaction(signum, act, oldact);
+ if (oldact) {
+ // The size of kernel_sigset_t is 8 bytes on every platform we care about.
+ // The rest of sa_mask is unused.
+ internal_memset((void *)((uptr)&oldact->sa_mask + 8), 0,
+ sizeof(oldact->sa_mask) - 8);
+ }
+ return res;
+}
+
// This class handles thread suspending/unsuspending in the tracer thread.
class ThreadSuspender {
public:
@@ -247,6 +267,29 @@
return exit_code;
}
+class ScopedStackSpaceWithGuard {
+ public:
+ explicit ScopedStackSpaceWithGuard(uptr stack_size) {
+ stack_size_ = stack_size;
+ guard_size_ = GetPageSizeCached();
+ // Omitting MAP_STACK here works in current kernels but might break later.
+ guard_start_ = (uptr) MmapOrDie(stack_size_ + guard_size_,
+ "ScopedStackWithGuard");
+ CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_));
+ }
+ ~ScopedStackSpaceWithGuard() {
+ UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_);
+ }
+ void *Bottom() const {
+ return (void *)(guard_start_ + stack_size_ + guard_size_);
+ }
+
+ private:
+ uptr stack_size_;
+ uptr guard_size_;
+ uptr guard_start_;
+};
+
static sigset_t blocked_sigset;
static sigset_t old_sigset;
static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
@@ -267,11 +310,10 @@
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,
- &old_sigactions[signal_index]);
+ CHECK_EQ(0, TidySigaction(kUnblockedSignals[signal_index], &new_sigaction,
+ &old_sigactions[signal_index]));
}
- int sigprocmask_status = sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
- CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
+ CHECK_EQ(0, sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset));
// Make this process dumpable. Processes that are not dumpable cannot be
// attached to.
int process_was_dumpable = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
@@ -281,16 +323,11 @@
struct TracerThreadArgument tracer_thread_argument;
tracer_thread_argument.callback = callback;
tracer_thread_argument.callback_argument = argument;
+ ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
// Block the execution of TracerThread until after we have set ptrace
// permissions.
tracer_thread_argument.mutex.Lock();
- // The tracer thread will run on the same stack, so we must reserve some
- // stack space for the caller thread to run in as it waits on the tracer.
- const uptr kReservedStackSize = 4096;
- // Get a 16-byte aligned pointer for stack.
- int a_local_variable __attribute__((__aligned__(16)));
- pid_t tracer_pid = clone(TracerThread,
- (char *)&a_local_variable - kReservedStackSize,
+ pid_t tracer_pid = clone(TracerThread, tracer_stack.Bottom(),
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
&tracer_thread_argument, 0, 0, 0);
if (tracer_pid < 0) {
@@ -318,8 +355,8 @@
// Restore the signal handlers.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- sigaction(kUnblockedSignals[signal_index],
- &old_sigactions[signal_index], NULL);
+ CHECK_EQ(0, TidySigaction(kUnblockedSignals[signal_index],
+ &old_sigactions[signal_index], NULL));
}
sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D592.2.patch
Type: text/x-patch
Size: 4634 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130330/47281576/attachment.bin>
More information about the llvm-commits
mailing list