Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1184)

Unified Diff: content/browser/download/mhtml_generation_manager.cc

Issue 2163073002: Avoid crashing if MHTMLGenerationManager::JobFinished is called twice. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Posting the injection ->UI->FILE->UI. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/download/mhtml_generation_manager.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/download/mhtml_generation_manager.cc
diff --git a/content/browser/download/mhtml_generation_manager.cc b/content/browser/download/mhtml_generation_manager.cc
index 60feca041a6491796bd906c67325edb11d6016e3..dc4ef122c219fa8b43ed5f04dfbd767d836eb906 100644
--- a/content/browser/download/mhtml_generation_manager.cc
+++ b/content/browser/download/mhtml_generation_manager.cc
@@ -44,11 +44,15 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
const GenerateMHTMLCallback& callback() const { return callback_; }
+ // Indicates whether we expect a message from the |sender| at this time.
+ // We expect only one message per frame - therefore calling this method
+ // will always clear |frame_tree_node_id_of_busy_frame_|.
+ bool IsMessageFromFrameExpected(RenderFrameHostImpl* sender);
+
// Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the
// renderer that the MHTML generation for previous frame has finished).
// Returns |true| upon success; |false| otherwise.
bool OnSerializeAsMHTMLResponse(
- RenderFrameHostImpl* sender,
const std::set<std::string>& digests_of_uris_of_serialized_resources);
// Sends IPC to the renderer, asking for MHTML generation of the next frame.
@@ -75,6 +79,8 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
int exit_code) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
+ void MarkAsFinished();
+
private:
static int64_t CloseFileOnFileThread(base::File file);
void AddFrame(RenderFrameHost* render_frame_host);
@@ -119,6 +125,11 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
// The callback to call once generation is complete.
const GenerateMHTMLCallback callback_;
+ // Whether the job is finished (set to true only for the short duration of
+ // time between MHTMLGenerationManager::JobFinished is called and the job is
+ // destroyed by MHTMLGenerationManager::OnFileClosed).
+ bool is_finished_;
+
// RAII helper for registering this Job as a RenderProcessHost observer.
ScopedObserver<RenderProcessHost, MHTMLGenerationManager::Job>
observed_renderer_process_host_;
@@ -136,6 +147,7 @@ MHTMLGenerationManager::Job::Job(int job_id,
mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()),
salt_(base::GenerateGUID()),
callback_(callback),
+ is_finished_(false),
observed_renderer_process_host_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_contents->ForEachFrame(base::Bind(
@@ -222,6 +234,15 @@ void MHTMLGenerationManager::Job::RenderProcessExited(
MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
}
+void MHTMLGenerationManager::Job::MarkAsFinished() {
+ DCHECK(!is_finished_);
+ is_finished_ = true;
+
+ // Stopping RenderProcessExited notifications is needed to avoid calling
+ // JobFinished twice. See also https://crbug.com/612098.
+ observed_renderer_process_host_.RemoveAll();
+}
+
void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) {
auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host);
int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id();
@@ -255,18 +276,21 @@ void MHTMLGenerationManager::Job::CloseFile(
callback);
}
-bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
- RenderFrameHostImpl* sender,
- const std::set<std::string>& digests_of_uris_of_serialized_resources) {
- // Sanitize renderer input / reject unexpected messages.
+bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected(
+ RenderFrameHostImpl* sender) {
int sender_id = sender->frame_tree_node()->frame_tree_node_id();
- if (sender_id != frame_tree_node_id_of_busy_frame_) {
- ReceivedBadMessage(sender->GetProcess(),
- bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
- return false; // Report failure.
- }
+ if (sender_id != frame_tree_node_id_of_busy_frame_)
+ return false;
+
+ // We only expect one message per frame - let's make sure subsequent messages
+ // from the same |sender| will be rejected.
frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId;
+ return true;
+}
+
+bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
+ const std::set<std::string>& digests_of_uris_of_serialized_resources) {
// Renderer should be deduping resources with the same uris.
DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>(
digests_of_already_serialized_uris_,
@@ -276,7 +300,7 @@ bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
digests_of_uris_of_serialized_resources.end());
if (pending_frame_tree_node_ids_.empty())
- return true; // Report success.
+ return true; // Report success - all frames have been processed.
return SendToNextRenderFrame();
}
@@ -323,7 +347,8 @@ void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
Job* job = FindJob(job_id);
- if (!job) {
+ if (!job || !job->IsMessageFromFrameExpected(sender)) {
+ NOTREACHED();
ReceivedBadMessage(sender->GetProcess(),
bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
return;
@@ -335,7 +360,7 @@ void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
}
if (!job->OnSerializeAsMHTMLResponse(
- sender, digests_of_uris_of_serialized_resources)) {
+ digests_of_uris_of_serialized_resources)) {
JobFinished(job, JobStatus::FAILURE);
return;
}
@@ -388,6 +413,7 @@ void MHTMLGenerationManager::JobFinished(Job* job, JobStatus job_status) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(job);
+ job->MarkAsFinished();
job->CloseFile(
base::Bind(&MHTMLGenerationManager::OnFileClosed,
base::Unretained(this), // Safe b/c |this| is a singleton.
« no previous file with comments | « content/browser/download/mhtml_generation_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698