Bug 1036286 - Delay registration of the faulty.lib signal handler until when it's necessary. r=nfroyd

It's necessary to delay it because for the second part, we need to call dlopen,
and until recently bionic's linker dead-locked when using dlopen from a static
initializer.
This commit is contained in:
Mike Hommey 2014-08-07 02:51:03 +09:00
parent 7f616e0548
commit 21f643ea4a
2 changed files with 35 additions and 14 deletions

View File

@ -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<TmpData*>(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 */

View File

@ -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;