diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index 28b4eb9bf7cb..9a62ff3d36dc 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -965,18 +965,18 @@ struct TmpData { }; SEGVHandler::SEGVHandler() -: registeredHandler(false), signalHandlingBroken(false) -, signalHandlingSlow(false) +: initialized(false), registeredHandler(false), signalHandlingBroken(true) +, signalHandlingSlow(true) { /* Initialize oldStack.ss_flags to an invalid value when used to set * an alternative stack, meaning we haven't got information about the - * original alternative stack and thus don't mean to restore it */ + * original alternative stack and thus don't mean to restore it in + * the destructor. */ oldStack.ss_flags = SS_ONSTACK; - if (!Divert(sigaction, __wrap_sigaction)) - return; /* Get the current segfault signal handler. */ - sys_sigaction(SIGSEGV, nullptr, &this->action); + struct sigaction old_action; + sys_sigaction(SIGSEGV, nullptr, &old_action); /* Some devices don't provide useful information to their SIGSEGV handlers, * making it impossible for on-demand decompression to work. To check if @@ -1005,11 +1005,23 @@ SEGVHandler::SEGVHandler() mprotect(stackPtr, stackPtr.GetLength(), PROT_NONE); data->crash_int = 123; /* Restore the original segfault signal handler. */ - sys_sigaction(SIGSEGV, &this->action, nullptr); + sys_sigaction(SIGSEGV, &old_action, nullptr); stackPtr.Assign(MAP_FAILED, 0); +} + +void +SEGVHandler::FinishInitialization() +{ + /* Ideally, we'd need some locking here, but in practice, we're not + * going to race with another thread. */ + initialized = true; + if (signalHandlingBroken || signalHandlingSlow) return; + if (!Divert(sigaction, __wrap_sigaction)) + return; + /* Setup an alternative stack if the already existing one is not big * enough, or if there is none. */ if (sigaltstack(nullptr, &oldStack) == 0) { @@ -1033,7 +1045,7 @@ SEGVHandler::SEGVHandler() * SEGVHandler's struct sigaction member */ action.sa_sigaction = &SEGVHandler::handler; action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; - registeredHandler = !sys_sigaction(SIGSEGV, &action, nullptr); + registeredHandler = !sys_sigaction(SIGSEGV, &action, &this->action); } SEGVHandler::~SEGVHandler() @@ -1053,18 +1065,18 @@ SEGVHandler::~SEGVHandler() void SEGVHandler::test_handler(int signum, siginfo_t *info, void *context) { SEGVHandler &that = ElfLoader::Singleton; - if (signum != SIGSEGV || - info == nullptr || info->si_addr != that.stackPtr.get()) - that.signalHandlingBroken = true; + if (signum == SIGSEGV && info && + info->si_addr == that.stackPtr.get()) + that.signalHandlingBroken = false; mprotect(that.stackPtr, that.stackPtr.GetLength(), PROT_READ | PROT_WRITE); TmpData *data = reinterpret_cast(that.stackPtr.get()); uint64_t latency = ProcessTimeStamp_Now() - data->crash_timestamp; DEBUG_LOG("SEGVHandler latency: %" PRIu64, latency); /* See bug 886736 for timings on different devices, 150 µs is reasonably above - * the latency on "working" devices and seems to be reasonably fast to incur + * the latency on "working" devices and seems to be short enough to not incur * a huge overhead to on-demand decompression. */ - if (latency > 150000) - that.signalHandlingSlow = true; + if (latency <= 150000) + that.signalHandlingSlow = false; } /* TODO: "properly" handle signal masks and flags */ diff --git a/mozglue/linker/ElfLoader.h b/mozglue/linker/ElfLoader.h index 0c59974e527c..65f2276636b0 100644 --- a/mozglue/linker/ElfLoader.h +++ b/mozglue/linker/ElfLoader.h @@ -312,6 +312,8 @@ class SEGVHandler { public: bool hasRegisteredHandler() { + if (! initialized) + FinishInitialization(); return registeredHandler; } @@ -327,6 +329,12 @@ private: static int __wrap_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); + /** + * The constructor doesn't do all initialization, and the tail is done + * at a later time. + */ + void FinishInitialization(); + /** * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction. */ @@ -359,6 +367,7 @@ private: */ MappedPtr stackPtr; + bool initialized; bool registeredHandler; bool signalHandlingBroken; bool signalHandlingSlow;