Add embedder test to help demonstrate FPDFPageObj_SetIsActive() crash
The newly added FPDFPageObj_SetIsActive() API can cause a crash in some
cases. Add a small test file that has the properties to trigger the
crash. Then add a test that exercises such a scenario and stops just
short of actually crashing.
Bug: 378120423
Change-Id: I211d11fbeda95e96035ad6aa6603db7fca32a31d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/125670
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_editpage_embeddertest.cpp b/fpdfsdk/fpdf_editpage_embeddertest.cpp
index 21ee8aa..25c9932 100644
--- a/fpdfsdk/fpdf_editpage_embeddertest.cpp
+++ b/fpdfsdk/fpdf_editpage_embeddertest.cpp
@@ -496,7 +496,7 @@
CloseSavedDocument();
}
-TEST_F(FPDFEditPageEmbedderTest, PageObjectIsActive) {
+TEST_F(FPDFEditPageEmbedderTest, PageObjectSetIsActive) {
const char* one_rectangle_inactive_checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
return "cf5bb4e61609162c03f4c8a6d9791230";
@@ -564,3 +564,54 @@
CloseSavedDocument();
}
}
+
+TEST_F(FPDFEditPageEmbedderTest, Bug378120423) {
+ const char kChecksum[] = "b53fb03e2bc41ef18d4ba61f0f681365";
+ const char kBlankChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
+
+ ASSERT_TRUE(OpenDocument("bug_378120423.pdf"));
+ ScopedEmbedderTestPage page = LoadScopedPage(0);
+ ASSERT_TRUE(page);
+ const int page_width = static_cast<int>(FPDF_GetPageWidth(page.get()));
+ const int page_height = static_cast<int>(FPDF_GetPageHeight(page.get()));
+
+ {
+ // Render the page as is.
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
+ CompareBitmap(bitmap.get(), page_width, page_height, kChecksum);
+ EXPECT_EQ(1, FPDFPage_CountObjects(page.get()));
+ }
+
+ // Deactivate `page_obj` and render.
+ FPDF_PAGEOBJECT page_obj = FPDFPage_GetObject(page.get(), 0);
+ ASSERT_TRUE(FPDFPageObj_SetIsActive(page_obj, false));
+ EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+ {
+ ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
+ CompareBitmap(bitmap.get(), page_width, page_height, kBlankChecksum);
+ // `page_obj` can still be found. It is just deactivated.
+ EXPECT_EQ(1, FPDFPage_CountObjects(page.get()));
+ }
+
+ {
+ // Save a copy, open the copy, and render it.
+ EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+ ASSERT_TRUE(OpenSavedDocument());
+ FPDF_PAGE saved_page = LoadSavedPage(0);
+ ASSERT_TRUE(saved_page);
+
+ ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
+ CompareBitmap(bitmap.get(), page_width, page_height, kBlankChecksum);
+ // `page_obj` did not get written out to the saved PDF.
+ EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
+
+ CloseSavedPage(saved_page);
+ CloseSavedDocument();
+ }
+
+ // Reactivate `page_obj` and render.
+ ASSERT_TRUE(FPDFPageObj_SetIsActive(page_obj, true));
+ // TODO(crbug.com/378120423): The test should be able to call
+ // FPDFPage_GenerateContent() without crashing. Then check the in-memory
+ // representation and the saved outputs.
+}
diff --git a/testing/resources/bug_378120423.in b/testing/resources/bug_378120423.in
new file mode 100644
index 0000000..a267f7b
--- /dev/null
+++ b/testing/resources/bug_378120423.in
@@ -0,0 +1,36 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /Count 1
+ /Kids [3 0 R]
+ /MediaBox [0 0 200 200]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+{{object 4 0}} <<
+{{streamlen}}
+>>
+stream
+q
+10 20 m
+10 30 l
+20 30 l
+h f
+Q
+endstream
+endobj
+
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/bug_378120423.pdf b/testing/resources/bug_378120423.pdf
new file mode 100644
index 0000000..a58b56d
--- /dev/null
+++ b/testing/resources/bug_378120423.pdf
@@ -0,0 +1,47 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /Count 1
+ /Kids [3 0 R]
+ /MediaBox [0 0 200 200]
+>>
+endobj
+3 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+>>
+endobj
+4 0 obj <<
+/Length 32
+>>
+stream
+q
+10 20 m
+10 30 l
+20 30 l
+h f
+Q
+endstream
+endobj
+
+xref
+0 5
+0000000000 65535 f
+0000000015 00000 n
+0000000068 00000 n
+0000000157 00000 n
+0000000226 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 5
+>>
+startxref
+308
+%%EOF