Commit 645f80c0 authored by Brian Hackett's avatar Brian Hackett
Browse files

Bug 1504372 - Always generate minidumps for replaying child crashes, r=mccr8.

--HG--
extra : rebase_source : f68f98127fc914339db47f57bf365a950ca2f2b4
parent cb45670d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ void
Channel::SendMessage(const Message& aMsg)
{
  MOZ_RELEASE_ASSERT(NS_IsMainThread() ||
                     aMsg.mType == MessageType::BeginFatalError ||
                     aMsg.mType == MessageType::FatalError ||
                     aMsg.mType == MessageType::MiddlemanCallRequest);

+7 −0
Original line number Diff line number Diff line
@@ -109,8 +109,13 @@ namespace recordreplay {
                                                               \
  /* A critical error occurred and execution cannot continue. The child will */ \
  /* stop executing after sending this message and will wait to be terminated. */ \
  /* A minidump for the child has been generated. */           \
  _Macro(FatalError)                                           \
                                                               \
  /* Sent when a fatal error has occurred, but before the minidump has been */ \
  /* generated. */                                             \
  _Macro(BeginFatalError)                                      \
                                                               \
  /* The child's graphics were repainted. */                   \
  _Macro(Paint)                                                \
                                                               \
@@ -371,6 +376,8 @@ struct FatalErrorMessage : public Message
  const char* Error() const { return Data<FatalErrorMessage, const char>(); }
};

typedef EmptyMessage<MessageType::BeginFatalError> BeginFatalErrorMessage;

// The format for graphics data which will be sent to the middleman process.
// This needs to match the format expected for canvas image data, to avoid
// transforming the data before rendering it in the middleman process.
+6 −1
Original line number Diff line number Diff line
@@ -108,8 +108,9 @@ ChannelMessageHandler(Message* aMsg)
      PrintSpew("Terminate message received, exiting...\n");
      _exit(0);
    } else {
      MOZ_CRASH("Hanged replaying process");
      ReportFatalError(Nothing(), "Hung replaying process");
    }
    break;
  }
  case MessageType::SetIsActive: {
    const SetIsActiveMessage& nmsg = (const SetIsActiveMessage&) *aMsg;
@@ -350,6 +351,10 @@ CreateCheckpoint()
void
ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
{
  // Notify the middleman that we are crashing and are going to try to write a
  // minidump.
  gChannel->SendMessage(BeginFatalErrorMessage());

  // Unprotect any memory which might be written while producing the minidump.
  UnrecoverableSnapshotFailure();

+23 −6
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ ChildProcessInfo::ChildProcessInfo(UniquePtr<ChildRole> aRole,
  , mNumRecoveredMessages(0)
  , mRole(std::move(aRole))
  , mPauseNeeded(false)
  , mHasBegunFatalError(false)
  , mHasFatalError(false)
{
  MOZ_RELEASE_ASSERT(NS_IsMainThread());

@@ -199,7 +201,11 @@ ChildProcessInfo::OnIncomingMessage(size_t aChannelId, const Message& aMsg)
  }

  // Always handle fatal errors in the same way.
  if (aMsg.mType == MessageType::FatalError) {
  if (aMsg.mType == MessageType::BeginFatalError) {
    mHasBegunFatalError = true;
    return;
  } else if (aMsg.mType == MessageType::FatalError) {
    mHasFatalError = true;
    const FatalErrorMessage& nmsg = static_cast<const FatalErrorMessage&>(aMsg);
    OnCrash(nmsg.Error());
    return;
@@ -527,14 +533,25 @@ ChildProcessInfo::OnCrash(const char* aWhy)
{
  MOZ_RELEASE_ASSERT(NS_IsMainThread());

  // If a child process crashes or hangs then annotate the crash report and
  // shut down cleanly so that we don't mask the report with our own crash.
  // We want the crash to happen quickly so the user doesn't get a hanged tab.
  // If a child process crashes or hangs then annotate the crash report.
  CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RecordReplayError,
                                     nsAutoCString(aWhy));

  // If we received a FatalError message then the child generated a minidump.
  // Shut down cleanly so that we don't mask the report with our own crash.
  if (mHasFatalError) {
    Shutdown();
  }

  // Indicate when we crash if the child tried to send us a fatal error message
  // but had a problem either unprotecting system memory or generating the
  // minidump.
  MOZ_RELEASE_ASSERT(!mHasBegunFatalError);

  // The child crashed without producing a minidump, produce one ourselves.
  MOZ_CRASH("Unexpected child crash");
}

///////////////////////////////////////////////////////////////////////////////
// Handling Channel Messages
///////////////////////////////////////////////////////////////////////////////
@@ -613,7 +630,7 @@ ChildProcessInfo::WaitUntil(const std::function<bool()>& aCallback)
            sentTerminateMessage = true;
          } else {
            // The child is still non-responsive after sending the terminate
            // message, fail without producing a minidump.
            // message.
            OnCrash("Child process non-responsive");
          }
        }
+5 −0
Original line number Diff line number Diff line
@@ -274,6 +274,11 @@ class ChildProcessInfo
  // Whether we need this child to pause while the recording is updated.
  bool mPauseNeeded;

  // Flags for whether we have received messages from the child indicating it
  // is crashing.
  bool mHasBegunFatalError;
  bool mHasFatalError;

  void OnIncomingMessage(size_t aChannelId, const Message& aMsg);
  void OnIncomingRecoveryMessage(const Message& aMsg);
  void SendNextRecoveryMessage();