0

Fix null-dereference in PrintRenderFrameHelper::PrintPageInternal()

Check if the RenderFrame still exists after rendering for printing, but
before rendering the headers/footers. Bail out if it is not. To let
PrintRenderFrameHelper know not to continue, change PrintPageInternal()
to return a result and check that in the callers. Then add an
appropriate PrintPreviewContext::set_error() calls and new error types
to handle the error when print previewing.

Bug: 371445200
Change-Id: I21f4273796d54db5f1602f42920b9d623ce77c41
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5955790
Reviewed-by: Alan Screen <awscreen@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#1373571}
This commit is contained in:
Lei Zhang
2024-10-24 20:58:59 +00:00
committed by Chromium LUCI CQ
parent 65fdaf60ba
commit 5d6835b376
3 changed files with 67 additions and 29 deletions
components/printing/renderer
tools/metrics/histograms

@ -29,6 +29,7 @@
#include "base/memory/shared_memory_mapping.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
@ -1838,26 +1839,41 @@ bool PrintRenderFrameHelper::RenderPreviewPage(
render_metafile->UtilizeTypefaceContext(
print_preview_context_.typeface_content_info());
base::TimeTicks begin_time = base::TimeTicks::Now();
PrintPageInternal(print_params, page_index,
print_preview_context_.total_page_count(),
print_preview_context_.prepared_frame(),
header_footer_frame, render_metafile);
print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
begin_time);
PrintPageInternalResult result = PrintPageInternal(
print_params, page_index, print_preview_context_.total_page_count(),
print_preview_context_.prepared_frame(), header_footer_frame,
render_metafile);
switch (result) {
case PrintPageInternalResult::kSuccess:
print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
begin_time);
// For non-modifiable content, there is no need to call PreviewPageRendered()
// since it generally renders very fast. Just render and send the finished
// document to the browser.
if (!print_preview_context_.IsModifiable())
return true;
// For non-modifiable content, there is no need to call
// PreviewPageRendered() since it generally renders very fast.
// Just render and send the finished document to the browser.
if (!print_preview_context_.IsModifiable()) {
return true;
}
// Let the browser know this page has been rendered. Send
// |page_render_metafile|, which contains the rendering for just this one
// page. Then the browser can update the user visible print preview one page
// at a time, instead of waiting for the entire document to be rendered.
page_render_metafile =
render_metafile->GetMetafileForCurrentPage(print_params.printed_doc_type);
return PreviewPageRendered(page_index, std::move(page_render_metafile));
// Let the browser know this page has been rendered. Send
// `page_render_metafile`, which contains the rendering for just this one
// page. Then the browser can update the user visible print preview one
// page at a time, instead of waiting for the entire document to be
// rendered.
page_render_metafile = render_metafile->GetMetafileForCurrentPage(
print_params.printed_doc_type);
return PreviewPageRendered(page_index, std::move(page_render_metafile));
case PrintPageInternalResult::kNoCanvas:
print_preview_context_.set_error(PrintPreviewErrorBuckets::kNoCanvas);
return false;
case PrintPageInternalResult::kNoRenderFrame:
print_preview_context_.set_error(
PrintPreviewErrorBuckets::kNoRenderFrame);
return false;
}
NOTREACHED();
}
bool PrintRenderFrameHelper::FinalizePrintReadyDocument() {
@ -2278,8 +2294,12 @@ bool PrintRenderFrameHelper::PrintPagesNative(
header_footer_frame = header_footer_context->frame();
}
for (uint32_t printed_page : printed_pages) {
PrintPageInternal(print_params, printed_page, page_count, frame,
header_footer_frame, &metafile);
PrintPageInternalResult result =
PrintPageInternal(print_params, printed_page, page_count, frame,
header_footer_frame, &metafile);
if (result != PrintPageInternalResult::kSuccess) {
return false;
}
}
}
@ -2488,7 +2508,8 @@ bool PrintRenderFrameHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
return true;
}
void PrintRenderFrameHelper::PrintPageInternal(
PrintRenderFrameHelper::PrintPageInternalResult
PrintRenderFrameHelper::PrintPageInternal(
const mojom::PrintParams& params,
uint32_t page_index,
uint32_t page_count,
@ -2530,12 +2551,16 @@ void PrintRenderFrameHelper::PrintPageInternal(
page_size_in_points, gfx::Rect(page_size_in_points),
kScaleFactorInPoints, layout.page_orientation);
}
if (!canvas)
return;
if (!canvas) {
return PrintPageInternalResult::kNoCanvas;
}
canvas->SetPrintingMetafile(metafile);
RenderPageContent(frame, page_index, canvas);
if (render_frame_gone_) {
return PrintPageInternalResult::kNoRenderFrame;
}
// Render headers and footers after the page content, as suggested in the spec
// (the term "page margin boxes" is a generalization of headers and footers):
@ -2552,6 +2577,8 @@ void PrintRenderFrameHelper::PrintPageInternal(
// Since `metafile` is known to have a non-null `canvas` at this point,
// FinishPage() cannot fail.
CHECK(ret);
return PrintPageInternalResult::kSuccess;
}
void PrintRenderFrameHelper::SetupOnStopLoadingTimeout() {

@ -207,6 +207,8 @@ class PrintRenderFrameHelper
// kInvalidPrinterSettingsDeprecated = 7,
// kMetafileCaptureFailedDeprecated = 8,
kEmptyPrinterSettings = 9,
kNoCanvas = 10,
kNoRenderFrame = 11,
kLastEnum // Always last.
};
@ -222,6 +224,12 @@ class PrintRenderFrameHelper
kScripted,
};
enum class PrintPageInternalResult {
kSuccess,
kNoCanvas,
kNoRenderFrame,
};
// Helper to make it easy to correctly call IPCReceived() and IPCProcessed().
class ScopedIPC {
public:
@ -367,12 +375,13 @@ class PrintRenderFrameHelper
const blink::WebNode& node);
// Helper function for rendering page at `page_index` to `metafile`.
void PrintPageInternal(const mojom::PrintParams& params,
uint32_t page_index,
uint32_t page_count,
blink::WebLocalFrame* frame,
blink::WebLocalFrame* header_footer_frame,
MetafileSkia* metafile);
PrintPageInternalResult PrintPageInternal(
const mojom::PrintParams& params,
uint32_t page_index,
uint32_t page_count,
blink::WebLocalFrame* frame,
blink::WebLocalFrame* header_footer_frame,
MetafileSkia* metafile);
// Helper methods -----------------------------------------------------------

@ -29230,6 +29230,8 @@ Called by update_net_error_codes.py.-->
<int value="7" label="Received bad printer settings (Deprecated)"/>
<int value="8" label="Capture metadata failed (Deprecated)"/>
<int value="9" label="Got empty printer settings"/>
<int value="10" label="No Canvas"/>
<int value="11" label="No RenderFrame"/>
</enum>
<enum name="PrivacySandboxAggregationServiceKeyFetcherStatus">