mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
7f616e0548
commit
21f643ea4a
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user