Ignore:
Timestamp:
Feb 7, 2017, 12:01:35 PM (8 years ago)
Author:
[email protected]
Message:

The SigillCrashAnalyzer should play nicer with client code that may install its own SIGILL handler.
https://bugs.webkit.org/show_bug.cgi?id=167858

Reviewed by Michael Saboff.

Here are the scenarios that may come up:

  1. Client code did not install a SIGILL handler.
    • In this case, once we're done analyzing the SIGILL, we can just restore the default handler and return to let the OS do the default action i.e. capture a core dump.
  1. Client code installed a SIGILL handler before JSC does.
    • In this case, we will see a non-null handler returned as the old signal handler when we install ours.
    • In our signal handler, after doing our crash analysis, we should invoke the client handler to let it do its work.
    • Our analyzer can also tell us if the SIGILL source is from JSC code in general (right now, this would just mean JIT code).
    • If the SIGILL source is not from JSC, we'll just let the client handler decided how to proceed. We assume that the client handler will do the right thing (which is how the old behavior is before the SigillCrashAnalyzer was introduced).
    • If the SIGILL source is from JSC, then we know the SIGILL is an unrecoverable condition. Hence, after we have given the client handler a chance to run, we should restore the default handler and let the OS capture a core dump. This intentionally overrides whatever signal settings the client handler may have set.
  1. Client code installed a SIGILL handler after JSC does.
    • In this case, we are dependent on the client handler to call our handler after it does its work. This is compatible with the old behavior before SigillCrashAnalyzer was introduced.
    • In our signal handler, if we determine that the SIGILL source is from JSC code, then the SIGILL is not recoverable. We should then restore the default handler and get a core dump.
    • If the SIGILL source is not from JSC, we check to see if there's a client handler installed after us.
    • If we detect a client handler installed after us, we defer judgement on what to do to the client handler. Since the client handler did not uninstall itself, it must have considered itself to have recovered from the SIGILL. We'll trust the client handler and take no restore action of our own (which is compatible with old code behavior).
    • If we detect no client handler and we have no previous handler, then we should restore the default handler and get a core dump.
  • tools/SigillCrashAnalyzer.cpp:

(JSC::handleCrash):
(JSC::installCrashHandler):
(JSC::SigillCrashAnalyzer::analyze): Deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp

    r211684 r211828  
    4848public:
    4949    static SigillCrashAnalyzer& instance();
    50     void analyze(SignalContext&);
     50
     51    enum class CrashSource {
     52        Unknown,
     53        JavaScriptCore,
     54        Other,
     55    };
     56    CrashSource analyze(SignalContext&);
    5157
    5258private:
     
    166172#endif
    167173
    168 struct sigaction oldSigIllAction;
    169 
    170 static void handleCrash(int, siginfo_t*, void* uap)
    171 {
    172     sigaction(SIGILL, &oldSigIllAction, nullptr);
    173 
     174struct sigaction originalSigIllAction;
     175
     176static void handleCrash(int signalNumber, siginfo_t* info, void* uap)
     177{
    174178    SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
    175179    SigillCrashAnalyzer& analyzer = SigillCrashAnalyzer::instance();
    176     analyzer.analyze(context);
     180    auto crashSource = analyzer.analyze(context);
     181
     182    auto originalAction = originalSigIllAction.sa_sigaction;
     183    if (originalAction) {
     184        // It is always safe to just invoke the original handler using the sa_sigaction form
     185        // without checking for the SA_SIGINFO flag. If the original handler is of the
     186        // sa_handler form, it will just ignore the 2nd and 3rd arguments since sa_handler is a
     187        // subset of sa_sigaction. This is what the man pages says the OS does anyway.
     188        originalAction(signalNumber, info, uap);
     189    }
     190
     191    if (crashSource == SigillCrashAnalyzer::CrashSource::JavaScriptCore) {
     192        // Restore the default handler so that we can get a core dump.
     193        struct sigaction defaultAction;
     194        defaultAction.sa_handler = SIG_DFL;
     195        sigfillset(&defaultAction.sa_mask);
     196        defaultAction.sa_flags = 0;
     197        sigaction(SIGILL, &defaultAction, nullptr);
     198    } else if (!originalAction) {
     199        // Pre-emptively restore the default handler but we may roll it back below.
     200        struct sigaction currentAction;
     201        struct sigaction defaultAction;
     202        defaultAction.sa_handler = SIG_DFL;
     203        sigfillset(&defaultAction.sa_mask);
     204        defaultAction.sa_flags = 0;
     205        sigaction(SIGILL, &defaultAction, &currentAction);
     206
     207        if (currentAction.sa_sigaction != handleCrash) {
     208            // This means that there's a client handler installed after us. This also means
     209            // that the client handler thinks it was able to recover from the SIGILL, and
     210            // did not uninstall itself. We can't argue with this because the crash isn't
     211            // known to be from a JavaScriptCore source. Hence, restore the client handler
     212            // and keep going.
     213            sigaction(SIGILL, &currentAction, nullptr);
     214        }
     215    }
    177216}
    178217
     
    184223    sigfillset(&action.sa_mask);
    185224    action.sa_flags = SA_SIGINFO;
    186     sigaction(SIGILL, &action, &oldSigIllAction);
     225    sigaction(SIGILL, &action, &originalSigIllAction);
    187226#else
    188227    UNUSED_PARAM(handleCrash);
     
    228267}
    229268
    230 void SigillCrashAnalyzer::analyze(SignalContext& context)
    231 {
     269auto SigillCrashAnalyzer::analyze(SignalContext& context) -> CrashSource
     270{
     271    CrashSource crashSource = CrashSource::Unknown;
    232272    log("BEGIN SIGILL analysis");
    233273
     
    258298        if (!isInJITMemory.value()) {
    259299            log("pc %p is NOT in valid JIT executable memory", pc);
     300            crashSource = CrashSource::Other;
    260301            return;
    261302        }
    262303        log("pc %p is in valid JIT executable memory", pc);
     304        crashSource = CrashSource::JavaScriptCore;
    263305
    264306#if CPU(ARM64)
     
    295337
    296338    log("END SIGILL analysis");
     339    return crashSource;
    297340}
    298341
Note: See TracChangeset for help on using the changeset viewer.