Fix an UnownedPtr error in CXFA_FFTabOrderPageWidgetIterator.
CPDFXFA_Page::GetNextXFAAnnot() and GetFirstOrLastXFAAnnot() can
potentially trigger an UnownedPtr error in
CXFA_FFTabOrderPageWidgetIterator. Fix the issue by using a RetainPtr to
ensure the object in question has the right live time.
This is a secondary issue from a previous bug report. Add a test case
for that.
Bug: chromium:980161
Change-Id: I895c3b6634aa0f7a68d2b44cc0307afc64716c78
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70252
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/testing/resources/javascript/xfa_specific/bug_980161.evt b/testing/resources/javascript/xfa_specific/bug_980161.evt
new file mode 100644
index 0000000..a5025fa
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_980161.evt
@@ -0,0 +1,4 @@
+mousemove,50,50
+mousedown,left,50,50
+mouseup,left,50,50
+keycode,9
diff --git a/testing/resources/javascript/xfa_specific/bug_980161.in b/testing/resources/javascript/xfa_specific/bug_980161.in
new file mode 100644
index 0000000..058444d
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_980161.in
@@ -0,0 +1,55 @@
+{{header}}
+{{include ../../xfa_catalog_1_0.fragment}}
+{{include ../../xfa_object_2_0.fragment}}
+{{include ../../xfa_preamble_3_0.fragment}}
+{{include ../../xfa_config_4_0.fragment}}
+{{object 5 0}} <<
+ {{streamlen}}
+>>
+stream
+<template xmlns="http://www.xfa.org/schema/xfa-template/2.6/">
+ <subform layout="tb" locale="en_US" name="form1" restoreState="auto">
+ <pageSet>
+ <pageArea id="Page1" name="Page1">
+ <contentArea h="10.5in" w="8in" x="0.25in" y="0.25in"/>
+ <medium long="11in" short="8.5in" stock="letter"/>
+ </pageArea>
+ </pageSet>
+ <subform h="10.5in" w="8in">
+ <field h="3mm" name="DropDownList1" w="3mm" x="0mm" y="1mm">
+ <ui>
+ <choiceList/>
+ </ui>
+ <items save="1">
+ <text>Single</text>
+ <text>Married</text>
+ <text>Other</text>
+ </items>
+ </field>
+ <field h="500.0001mm" name="DropDownList2" w="500.625mm" x="0mm" y="0mm">
+ <ui>
+ <textEdit></textEdit>
+ </ui>
+ <traversal>
+ <traverse operation="next" ref="$xfa.(eval('xfa.host.setFocus(field_DropDownList1); xfa.template.remerge(); xfa.host.openList(field_DropDownList1);') == 0)"/>
+ </traversal>
+ </field>
+ </subform>
+ <event activity="docReady">
+ <script contentType="application/x-javascript">
+ field_DropDownList1 = xfa.resolveNode("xfa.form..DropDownList1");
+ field_DropDownList2 = xfa.resolveNode("xfa.form..DropDownList2");
+ xfa.host.setFocus(field_DropDownList2);
+ </script>
+ </event>
+ </subform>
+</template>
+endstream
+endobj
+{{include ../../xfa_locale_6_0.fragment}}
+{{include ../../xfa_postamble_7_0.fragment}}
+{{include ../../xfa_pages_8_0.fragment}}
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/xfa/fxfa/cxfa_ffpageview.cpp b/xfa/fxfa/cxfa_ffpageview.cpp
index 45a4ddc..3e3a7a4 100644
--- a/xfa/fxfa/cxfa_ffpageview.cpp
+++ b/xfa/fxfa/cxfa_ffpageview.cpp
@@ -238,7 +238,7 @@
CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator(
CXFA_FFPageView* pPageView,
uint32_t dwFilter)
- : m_pPageView(pPageView),
+ : m_pPageViewLayout(pPageView->GetLayoutItem()),
m_dwFilter(dwFilter),
m_bIgnoreRelevant(IsDocVersionBelow205(GetDocForPageView(pPageView))) {
Reset();
@@ -442,7 +442,7 @@
void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray(
std::vector<CXFA_FFWidget*>* WidgetArray) {
- CXFA_LayoutItemIterator sIterator(m_pPageView->GetLayoutItem());
+ CXFA_LayoutItemIterator sIterator(m_pPageViewLayout.Get());
auto pParam = std::make_unique<CXFA_TabParam>(nullptr);
bool bCurrentItem = false;
bool bContentArea = false;
diff --git a/xfa/fxfa/cxfa_ffpageview.h b/xfa/fxfa/cxfa_ffpageview.h
index a4ecb3d..1025046 100644
--- a/xfa/fxfa/cxfa_ffpageview.h
+++ b/xfa/fxfa/cxfa_ffpageview.h
@@ -108,7 +108,7 @@
bool bMasterPage);
std::vector<RetainPtr<CXFA_ContentLayoutItem>> m_TabOrderWidgetArray;
- UnownedPtr<CXFA_FFPageView> const m_pPageView;
+ RetainPtr<CXFA_ViewLayoutItem> const m_pPageViewLayout;
const uint32_t m_dwFilter;
int32_t m_iCurWidget = -1;
const bool m_bIgnoreRelevant;