summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Sepez <tsepez@chromium.org>2015-09-09 09:58:10 -0700
committerTom Sepez <tsepez@chromium.org>2015-09-09 09:58:10 -0700
commit9241e5a43990859f6f9a94aaa2c488d0451039e3 (patch)
treed59fa133dccca79cb9b2e9da5930cae8aa6ad75e
parent343dbb841f4c12e819932e2b66dd70f817337d97 (diff)
downloadpdfium-9241e5a43990859f6f9a94aaa2c488d0451039e3.tar.xz
Fix heap use after free in CPDFSDK_Annot::GetPDFAnnot.
Use two seperate loops to kill current focus annot and to release annots in current page. Loop to kill current focus annot is run first, so it will not access deleted annots. BUG=507316 R=tsepez@chromium.org TEST=Reproduction steps mentioned in issue 507316 should not crash chrome. Unit test added to pdfium. Run pdfium_embeddertests.exe. Review URL: https://codereview.chromium.org/1312313006 .
-rw-r--r--fpdfsdk/src/fpdfformfill_embeddertest.cpp12
-rw-r--r--fpdfsdk/src/fsdk_mgr.cpp22
-rw-r--r--testing/embedder_test.cpp34
-rw-r--r--testing/embedder_test.h16
4 files changed, 76 insertions, 8 deletions
diff --git a/fpdfsdk/src/fpdfformfill_embeddertest.cpp b/fpdfsdk/src/fpdfformfill_embeddertest.cpp
index 6baad11531..56710b9f83 100644
--- a/fpdfsdk/src/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/src/fpdfformfill_embeddertest.cpp
@@ -40,6 +40,18 @@ TEST_F(FPDFFormFillEmbeddertest, BUG_487928) {
UnloadPage(page);
}
+TEST_F(FPDFFormFillEmbeddertest, BUG_507316) {
+ EmbedderTestTimerHandlingDelegate delegate;
+ SetDelegate(&delegate);
+
+ EXPECT_TRUE(OpenDocument("testing/resources/bug_507316.pdf"));
+ FPDF_PAGE page = LoadAndCachePage(2);
+ EXPECT_NE(nullptr, page);
+ DoOpenActions();
+ delegate.AdvanceTime(4000);
+ UnloadPage(page);
+}
+
TEST_F(FPDFFormFillEmbeddertest, BUG_514690) {
EXPECT_TRUE(OpenDocument("testing/resources/hello_world.pdf"));
FPDF_PAGE page = LoadPage(0);
diff --git a/fpdfsdk/src/fsdk_mgr.cpp b/fpdfsdk/src/fsdk_mgr.cpp
index 3eca559285..9cbb9de4d9 100644
--- a/fpdfsdk/src/fsdk_mgr.cpp
+++ b/fpdfsdk/src/fsdk_mgr.cpp
@@ -634,16 +634,22 @@ CPDFSDK_PageView::CPDFSDK_PageView(CPDFSDK_Document* pSDKDoc, CPDF_Page* page)
}
CPDFSDK_PageView::~CPDFSDK_PageView() {
- CPDFDoc_Environment* pEnv = m_pSDKDoc->GetEnv();
- int nAnnotCount = m_fxAnnotArray.GetSize();
+ // if there is a focused annot on the page, we should kill the focus first.
+ if (CPDFSDK_Annot* focusedAnnot = m_pSDKDoc->GetFocusAnnot()) {
+ for (int i = 0, count = m_fxAnnotArray.GetSize(); i < count; i++) {
+ CPDFSDK_Annot* pAnnot = (CPDFSDK_Annot*)m_fxAnnotArray.GetAt(i);
+ if (pAnnot == focusedAnnot) {
+ KillFocusAnnot();
+ break;
+ }
+ }
+ }
- for (int i = 0; i < nAnnotCount; i++) {
+ CPDFDoc_Environment* pEnv = m_pSDKDoc->GetEnv();
+ CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr = pEnv->GetAnnotHandlerMgr();
+ ASSERT(pAnnotHandlerMgr);
+ for (int i = 0, count = m_fxAnnotArray.GetSize(); i < count; i++) {
CPDFSDK_Annot* pAnnot = (CPDFSDK_Annot*)m_fxAnnotArray.GetAt(i);
- // if there is a focused annot on the page, we should kill the focus first.
- if (pAnnot == m_pSDKDoc->GetFocusAnnot())
- KillFocusAnnot();
- CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr = pEnv->GetAnnotHandlerMgr();
- ASSERT(pAnnotHandlerMgr);
pAnnotHandlerMgr->ReleaseAnnot(pAnnot);
}
m_fxAnnotArray.RemoveAll();
diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp
index 1476522e57..eb16bc70f9 100644
--- a/testing/embedder_test.cpp
+++ b/testing/embedder_test.cpp
@@ -221,6 +221,7 @@ bool EmbedderTest::OpenDocument(const std::string& filename) {
formfillinfo->version = 1;
formfillinfo->FFI_SetTimer = SetTimerTrampoline;
formfillinfo->FFI_KillTimer = KillTimerTrampoline;
+ formfillinfo->FFI_GetPage = GetPageTrampoline;
formfillinfo->m_pJsPlatform = platform;
form_handle_ = FPDFDOC_InitFormFillEnvironment(document_, formfillinfo);
@@ -259,6 +260,15 @@ FPDF_PAGE EmbedderTest::LoadPage(int page_number) {
return page;
}
+FPDF_PAGE EmbedderTest::LoadAndCachePage(int page_number) {
+ FPDF_PAGE page = delegate_->GetPage(form_handle_, document_, page_number);
+ if (!page) {
+ return nullptr;
+ }
+ FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_OPEN);
+ return page;
+}
+
FPDF_BITMAP EmbedderTest::RenderPage(FPDF_PAGE page) {
int width = static_cast<int>(FPDF_GetPageWidth(page));
int height = static_cast<int>(FPDF_GetPageHeight(page));
@@ -275,6 +285,22 @@ void EmbedderTest::UnloadPage(FPDF_PAGE page) {
FPDF_ClosePage(page);
}
+FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMHANDLE form_handle,
+ FPDF_DOCUMENT document,
+ int page_index) {
+ auto it = m_pageMap.find(page_index);
+ if (it != m_pageMap.end()) {
+ return it->second;
+ }
+ FPDF_PAGE page = FPDF_LoadPage(document, page_index);
+ if (!page) {
+ return nullptr;
+ }
+ m_pageMap[page_index] = page;
+ FORM_OnAfterLoadPage(page, form_handle);
+ return page;
+}
+
// static
void EmbedderTest::UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info,
int type) {
@@ -306,6 +332,14 @@ void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
return test->delegate_->KillTimer(id);
}
+// static
+FPDF_PAGE EmbedderTest::GetPageTrampoline(FPDF_FORMFILLINFO* info,
+ FPDF_DOCUMENT document,
+ int page_index) {
+ EmbedderTest* test = static_cast<EmbedderTest*>(info);
+ return test->delegate_->GetPage(test->m_pFormfillinfo, document, page_index);
+}
+
// Can't use gtest-provided main since we need to stash the path to the
// executable in order to find the external V8 binary data files.
int main(int argc, char** argv) {
diff --git a/testing/embedder_test.h b/testing/embedder_test.h
index 4bd9d9713e..f490f82536 100644
--- a/testing/embedder_test.h
+++ b/testing/embedder_test.h
@@ -5,6 +5,7 @@
#ifndef TESTING_EMBEDDER_TEST_H_
#define TESTING_EMBEDDER_TEST_H_
+#include <map>
#include <string>
#include "../public/fpdf_dataavail.h"
@@ -43,6 +44,14 @@ class EmbedderTest : public ::testing::Test,
// Equivalent to FPDF_FORMFILLINFO::FFI_KillTimer().
virtual void KillTimer(int id) {}
+
+ // Equivalent to FPDF_FORMFILLINFO::FFI_GetPage().
+ virtual FPDF_PAGE GetPage(FPDF_FORMHANDLE form_handle,
+ FPDF_DOCUMENT document,
+ int page_index);
+
+ private:
+ std::map<int, FPDF_PAGE> m_pageMap;
};
EmbedderTest();
@@ -72,6 +81,10 @@ class EmbedderTest : public ::testing::Test,
// Load a specific page of the open document.
virtual FPDF_PAGE LoadPage(int page_number);
+ // Load a specific page of the open document using delegate_->GetPage.
+ // delegate_->GetPage also caches loaded page.
+ virtual FPDF_PAGE LoadAndCachePage(int page_number);
+
// Convert a loaded page into a bitmap.
virtual FPDF_BITMAP RenderPage(FPDF_PAGE page);
@@ -106,6 +119,9 @@ class EmbedderTest : public ::testing::Test,
int msecs,
TimerCallback fn);
static void KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id);
+ static FPDF_PAGE GetPageTrampoline(FPDF_FORMFILLINFO* info,
+ FPDF_DOCUMENT document,
+ int page_index);
};
#endif // TESTING_EMBEDDER_TEST_H_