Commit f050c89a authored by rockot's avatar rockot Committed by Commit bot

Better bad message reporting from IO thread

This makes crash dumping optional for RPH::ShutdownForBadMessage,
and changes the thread-safe bad_message::ReceivedBadMessage to
generate its own crash dump immediately, before potentially posting
a UI thread task.

All other call sites have been updated to opt into crash dumping,
preserving previous behavior.

This ensures that bad message reports from the IO thread have a
useful crash stack.

BUG=652755
R=jam@chromium.org

Review-Url: https://codereview.chromium.org/2387113004
Cr-Commit-Position: refs/heads/master@{#423040}
parent 0eac373e
...@@ -23,7 +23,8 @@ void LogBadMessage(BadMessageReason reason) { ...@@ -23,7 +23,8 @@ void LogBadMessage(BadMessageReason reason) {
void ReceivedBadMessage(content::RenderProcessHost* host, void ReceivedBadMessage(content::RenderProcessHost* host,
BadMessageReason reason) { BadMessageReason reason) {
LogBadMessage(reason); LogBadMessage(reason);
host->ShutdownForBadMessage(); host->ShutdownForBadMessage(
content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
} }
void ReceivedBadMessage(content::BrowserMessageFilter* filter, void ReceivedBadMessage(content::BrowserMessageFilter* filter,
......
...@@ -18,7 +18,8 @@ void ReceivedBadMessage(content::RenderProcessHost* host, ...@@ -18,7 +18,8 @@ void ReceivedBadMessage(content::RenderProcessHost* host,
<< static_cast<int>(reason); << static_cast<int>(reason);
UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.PasswordManager", UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.PasswordManager",
static_cast<int>(reason)); static_cast<int>(reason));
host->ShutdownForBadMessage(); host->ShutdownForBadMessage(
content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
} }
} // namespace bad_message } // namespace bad_message
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/debug/crash_logging.h" #include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/sparse_histogram.h" #include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -29,18 +30,29 @@ void ReceivedBadMessageOnUIThread(int render_process_id, ...@@ -29,18 +30,29 @@ void ReceivedBadMessageOnUIThread(int render_process_id,
BadMessageReason reason) { BadMessageReason reason) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RenderProcessHost* host = RenderProcessHost::FromID(render_process_id); RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
if (host) if (!host)
ReceivedBadMessage(host, reason); return;
LogBadMessage(reason);
// A dump has already been generated by the caller. Don't generate another.
host->ShutdownForBadMessage(
RenderProcessHost::CrashReportMode::NO_CRASH_DUMP);
} }
} // namespace } // namespace
void ReceivedBadMessage(RenderProcessHost* host, BadMessageReason reason) { void ReceivedBadMessage(RenderProcessHost* host, BadMessageReason reason) {
LogBadMessage(reason); LogBadMessage(reason);
host->ShutdownForBadMessage(); host->ShutdownForBadMessage(
RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
} }
void ReceivedBadMessage(int render_process_id, BadMessageReason reason) { void ReceivedBadMessage(int render_process_id, BadMessageReason reason) {
// We generate a crash dump here since generating one after posting the UI
// thread is mostly useless.
base::debug::DumpWithoutCrashing();
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::UI, BrowserThread::UI,
......
...@@ -36,7 +36,8 @@ void BrowserMediaSessionManager::OnSetMetadata( ...@@ -36,7 +36,8 @@ void BrowserMediaSessionManager::OnSetMetadata(
// coming from a known and secure source. It must be processed accordingly. // coming from a known and secure source. It must be processed accordingly.
if (insecure_metadata.has_value() && if (insecure_metadata.has_value() &&
!MediaMetadataSanitizer::CheckSanity(insecure_metadata.value())) { !MediaMetadataSanitizer::CheckSanity(insecure_metadata.value())) {
render_frame_host_->GetProcess()->ShutdownForBadMessage(); render_frame_host_->GetProcess()->ShutdownForBadMessage(
RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
return; return;
} }
......
...@@ -972,9 +972,7 @@ bool RenderProcessHostImpl::Init() { ...@@ -972,9 +972,7 @@ bool RenderProcessHostImpl::Init() {
child_process_launcher_.reset(new ChildProcessLauncher( child_process_launcher_.reset(new ChildProcessLauncher(
new RendererSandboxedProcessLauncherDelegate(channel_.get()), cmd_line, new RendererSandboxedProcessLauncherDelegate(channel_.get()), cmd_line,
GetID(), this, child_token_, GetID(), this, child_token_,
base::Bind(&RenderProcessHostImpl::OnMojoError, base::Bind(&RenderProcessHostImpl::OnMojoError, id_)));
weak_factory_.GetWeakPtr(),
base::ThreadTaskRunnerHandle::Get())));
channel_->Pause(); channel_->Pause();
fast_shutdown_started_ = false; fast_shutdown_started_ = false;
...@@ -1463,7 +1461,8 @@ void RenderProcessHostImpl::RemoveObserver( ...@@ -1463,7 +1461,8 @@ void RenderProcessHostImpl::RemoveObserver(
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
void RenderProcessHostImpl::ShutdownForBadMessage() { void RenderProcessHostImpl::ShutdownForBadMessage(
CrashReportMode crash_report_mode) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC)) if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
return; return;
...@@ -1478,8 +1477,10 @@ void RenderProcessHostImpl::ShutdownForBadMessage() { ...@@ -1478,8 +1477,10 @@ void RenderProcessHostImpl::ShutdownForBadMessage() {
// browser to try to survive when it gets illegal messages from the renderer. // browser to try to survive when it gets illegal messages from the renderer.
Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE, false); Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE, false);
// Report a crash, since none will be generated by the killed renderer. if (crash_report_mode == CrashReportMode::GENERATE_CRASH_DUMP) {
base::debug::DumpWithoutCrashing(); // Report a crash, since none will be generated by the killed renderer.
base::debug::DumpWithoutCrashing();
}
// Log the renderer kill to the histogram tracking all kills. // Log the renderer kill to the histogram tracking all kills.
BrowserChildProcessHostImpl::HistogramBadMessageTerminated( BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
...@@ -3031,24 +3032,14 @@ void RenderProcessHostImpl::RecomputeAndUpdateWebKitPreferences() { ...@@ -3031,24 +3032,14 @@ void RenderProcessHostImpl::RecomputeAndUpdateWebKitPreferences() {
} }
// static // static
void RenderProcessHostImpl::OnMojoError( void RenderProcessHostImpl::OnMojoError(int render_process_id,
base::WeakPtr<RenderProcessHostImpl> process, const std::string& error) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const std::string& error) {
if (!task_runner->BelongsToCurrentThread()) {
task_runner->PostTask(FROM_HERE,
base::Bind(&RenderProcessHostImpl::OnMojoError,
process, task_runner, error));
return;
}
if (!process)
return;
LOG(ERROR) << "Terminating render process for bad Mojo message: " << error; LOG(ERROR) << "Terminating render process for bad Mojo message: " << error;
// The ReceivedBadMessage call below will trigger a DumpWithoutCrashing. Alias // The ReceivedBadMessage call below will trigger a DumpWithoutCrashing. Alias
// enough information here so that we can determine what the bad message was. // enough information here so that we can determine what the bad message was.
base::debug::Alias(&error); base::debug::Alias(&error);
bad_message::ReceivedBadMessage(process.get(), bad_message::ReceivedBadMessage(render_process_id,
bad_message::RPH_MOJO_PROCESS_ERROR); bad_message::RPH_MOJO_PROCESS_ERROR);
} }
......
...@@ -121,7 +121,7 @@ class CONTENT_EXPORT RenderProcessHostImpl ...@@ -121,7 +121,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void RemoveRoute(int32_t routing_id) override; void RemoveRoute(int32_t routing_id) override;
void AddObserver(RenderProcessHostObserver* observer) override; void AddObserver(RenderProcessHostObserver* observer) override;
void RemoveObserver(RenderProcessHostObserver* observer) override; void RemoveObserver(RenderProcessHostObserver* observer) override;
void ShutdownForBadMessage() override; void ShutdownForBadMessage(CrashReportMode crash_report_mode) override;
void WidgetRestored() override; void WidgetRestored() override;
void WidgetHidden() override; void WidgetHidden() override;
int VisibleWidgetCount() const override; int VisibleWidgetCount() const override;
...@@ -378,10 +378,7 @@ class CONTENT_EXPORT RenderProcessHostImpl ...@@ -378,10 +378,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
base::FilePath GetAecDumpFilePathWithExtensions(const base::FilePath& file); base::FilePath GetAecDumpFilePathWithExtensions(const base::FilePath& file);
#endif #endif
static void OnMojoError( static void OnMojoError(int render_process_id, const std::string& error);
base::WeakPtr<RenderProcessHostImpl> process,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const std::string& error);
template <typename InterfaceType> template <typename InterfaceType>
using AddInterfaceCallback = using AddInterfaceCallback =
......
...@@ -65,6 +65,12 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender, ...@@ -65,6 +65,12 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
int exit_code; int exit_code;
}; };
// Crash reporting mode for ShutdownForBadMessage.
enum class CrashReportMode {
NO_CRASH_DUMP,
GENERATE_CRASH_DUMP,
};
// General functions --------------------------------------------------------- // General functions ---------------------------------------------------------
~RenderProcessHost() override {} ~RenderProcessHost() override {}
...@@ -95,7 +101,10 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender, ...@@ -95,7 +101,10 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
// Most callers should not call this directly, but instead should call // Most callers should not call this directly, but instead should call
// bad_message::BadMessageReceived() or an equivalent method outside of the // bad_message::BadMessageReceived() or an equivalent method outside of the
// content module. // content module.
virtual void ShutdownForBadMessage() = 0; //
// If |crash_report_mode| is GENERATE_CRASH_DUMP, then a browser crash dump
// will be reported as well.
virtual void ShutdownForBadMessage(CrashReportMode crash_report_mode) = 0;
// Track the count of visible widgets. Called by listeners to register and // Track the count of visible widgets. Called by listeners to register and
// unregister visibility. // unregister visibility.
......
...@@ -128,7 +128,8 @@ void MockRenderProcessHost::RemoveObserver( ...@@ -128,7 +128,8 @@ void MockRenderProcessHost::RemoveObserver(
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
void MockRenderProcessHost::ShutdownForBadMessage() { void MockRenderProcessHost::ShutdownForBadMessage(
CrashReportMode crash_report_mode) {
++bad_msg_count_; ++bad_msg_count_;
} }
......
...@@ -50,7 +50,7 @@ class MockRenderProcessHost : public RenderProcessHost { ...@@ -50,7 +50,7 @@ class MockRenderProcessHost : public RenderProcessHost {
void RemoveRoute(int32_t routing_id) override; void RemoveRoute(int32_t routing_id) override;
void AddObserver(RenderProcessHostObserver* observer) override; void AddObserver(RenderProcessHostObserver* observer) override;
void RemoveObserver(RenderProcessHostObserver* observer) override; void RemoveObserver(RenderProcessHostObserver* observer) override;
void ShutdownForBadMessage() override; void ShutdownForBadMessage(CrashReportMode crash_report_mode) override;
void WidgetRestored() override; void WidgetRestored() override;
void WidgetHidden() override; void WidgetHidden() override;
int VisibleWidgetCount() const override; int VisibleWidgetCount() const override;
......
...@@ -17,7 +17,8 @@ void ReceivedBadMessage(content::RenderProcessHost* host, ...@@ -17,7 +17,8 @@ void ReceivedBadMessage(content::RenderProcessHost* host,
<< reason; << reason;
UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.Extensions", UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.Extensions",
reason); reason);
host->ShutdownForBadMessage(); host->ShutdownForBadMessage(
content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
} }
} // namespace bad_message } // namespace bad_message
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment