From b835d2bd66fcac7afddae163a87d0b6f4cd6100f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 18 Oct 2023 11:46:11 -0400 Subject: [PATCH] LibPDF: Use a RAII object to restore state in recursive render Previously, if one operator returned an error, the TRY() would cause us to return without restoring the outer graphics state, leading to problems such as handing a 3-tuple to a grayscale color space (because the inner object set up a grayscale color space that we failed to dispose of). Makes us crash later on page 43 of https://devstreaming-cdn.apple.com/videos/wwdc/2017/821kjtggolzxsv/821/821_get_started_with_display_p3.pdf --- Userland/Libraries/LibPDF/Renderer.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index a306eb48557..f3eaf0b1603 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -644,7 +644,25 @@ RENDERER_HANDLER(paint_xobject) return {}; } - MUST(handle_save_state({})); + // Use a RAII object to restore the graphics state, to make sure it gets restored even if + // a TRY(handle_operator()) causes us to exit the operators loop early. + class ScopedState { + public: + ScopedState(Renderer& renderer) + : m_renderer(renderer) + { + MUST(m_renderer.handle_save_state({})); + } + ~ScopedState() + { + MUST(m_renderer.handle_restore_state({})); + } + + private: + Renderer& m_renderer; + }; + ScopedState scoped_state { *this }; + Vector matrix; if (xobject->dict()->contains(CommonNames::Matrix)) { matrix = xobject->dict()->get_array(m_document, CommonNames::Matrix).value()->elements(); @@ -655,7 +673,6 @@ RENDERER_HANDLER(paint_xobject) auto operators = TRY(Parser::parse_operators(m_document, xobject->bytes())); for (auto& op : operators) TRY(handle_operator(op, xobject_resources)); - MUST(handle_restore_state({})); return {}; }