Fix FPDF_FILEACCESS lifetime issue with FPDF_LoadCustomDocument().
The FPDF_FILEACCESS that gets passed to FPDF_LoadCustomDocument() does
not need to outlive the returned FPDF_DOCUMENT. See bug for discussion.
This is a partial revert of commit b2ae83e8, along with a test case for
this scenario and a clarification in the public API comments.
BUG=pdfium:1261
Change-Id: Ib1d1b759fe3af98aa4ecc1d8387a259ee4ffe07f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/51570
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_customaccess.cpp b/fpdfsdk/cpdfsdk_customaccess.cpp
index fcaede5..acdf93a 100644
--- a/fpdfsdk/cpdfsdk_customaccess.cpp
+++ b/fpdfsdk/cpdfsdk_customaccess.cpp
@@ -7,14 +7,12 @@
#include "fpdfsdk/cpdfsdk_customaccess.h"
CPDFSDK_CustomAccess::CPDFSDK_CustomAccess(FPDF_FILEACCESS* pFileAccess)
- : m_pFileAccess(pFileAccess) {
- ASSERT(m_pFileAccess);
-}
+ : m_FileAccess(*pFileAccess) {}
CPDFSDK_CustomAccess::~CPDFSDK_CustomAccess() = default;
FX_FILESIZE CPDFSDK_CustomAccess::GetSize() {
- return m_pFileAccess->m_FileLen;
+ return m_FileAccess.m_FileLen;
}
bool CPDFSDK_CustomAccess::ReadBlockAtOffset(void* buffer,
@@ -26,6 +24,6 @@
FX_SAFE_FILESIZE new_pos = pdfium::base::checked_cast<FX_FILESIZE>(size);
new_pos += offset;
return new_pos.IsValid() && new_pos.ValueOrDie() <= GetSize() &&
- m_pFileAccess->m_GetBlock(m_pFileAccess->m_Param, offset,
- static_cast<uint8_t*>(buffer), size);
+ m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset,
+ static_cast<uint8_t*>(buffer), size);
}
diff --git a/fpdfsdk/cpdfsdk_customaccess.h b/fpdfsdk/cpdfsdk_customaccess.h
index 341d4ab..76940ce 100644
--- a/fpdfsdk/cpdfsdk_customaccess.h
+++ b/fpdfsdk/cpdfsdk_customaccess.h
@@ -25,7 +25,7 @@
explicit CPDFSDK_CustomAccess(FPDF_FILEACCESS* pFileAccess);
~CPDFSDK_CustomAccess() override;
- UnownedPtr<FPDF_FILEACCESS> const m_pFileAccess;
+ FPDF_FILEACCESS m_FileAccess;
};
#endif // FPDFSDK_CPDFSDK_CUSTOMACCESS_H_
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index cade1ca..3a314ba 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -276,6 +276,37 @@
EXPECT_FALSE(FPDF_LoadCustomDocument(nullptr, ""));
}
+// See https://crbug.com/pdfium/1261
+TEST_F(FPDFViewEmbedderTest, LoadCustomDocumentWithShortLivedFileAccess) {
+ std::string file_contents_string; // Must outlive |doc|.
+ ScopedFPDFDocument doc;
+ {
+ // Read a PDF, and copy it into |file_contents_string|.
+ std::string pdf_path;
+ size_t pdf_length;
+ ASSERT_TRUE(PathService::GetTestFilePath("rectangles.pdf", &pdf_path));
+ auto file_contents = GetFileContents(pdf_path.c_str(), &pdf_length);
+ ASSERT_TRUE(file_contents);
+ for (size_t i = 0; i < pdf_length; ++i)
+ file_contents_string.push_back(file_contents.get()[i]);
+
+ // Define a FPDF_FILEACCESS object that will go out of scope, while the
+ // loaded document in |doc| remains valid.
+ FPDF_FILEACCESS file_access = {};
+ file_access.m_FileLen = pdf_length;
+ file_access.m_GetBlock = GetBlockFromString;
+ file_access.m_Param = &file_contents_string;
+ doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
+ ASSERT_TRUE(doc);
+ }
+
+ // Now try to access |doc| and make sure it still works.
+ ScopedFPDFPage page(FPDF_LoadPage(doc.get(), 0));
+ ASSERT_TRUE(page);
+ EXPECT_DOUBLE_EQ(200, FPDF_GetPageWidth(page.get()));
+ EXPECT_DOUBLE_EQ(300, FPDF_GetPageHeight(page.get()));
+}
+
TEST_F(FPDFViewEmbedderTest, Page) {
EXPECT_TRUE(OpenDocument("about_blank.pdf"));
FPDF_PAGE page = LoadPage(0);
diff --git a/public/fpdfview.h b/public/fpdfview.h
index acd7400..8892da5 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -453,10 +453,11 @@
// Return value:
// A handle to the loaded document, or NULL on failure.
// Comments:
-// The application must keep the file resources valid until the PDF
-// document is closed.
+// The application must keep the file resources |pFileAccess| points to
+// valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|
+// itself does not need to outlive the FPDF_DOCUMENT.
//
-// The loaded document can be closed with FPDF_CloseDocument.
+// The loaded document can be closed with FPDF_CloseDocument().
//
// See the comments for FPDF_LoadDocument() regarding the encoding for
// |password|.