Handle re-entrancy during form field focus transitions Track CFFL_FormField lifetime using ObservedPtr during focus transitions and PWL window updates. Return early if the form field is destroyed while handling these events. Fixed: 567936263 Change-Id: I992b06f6bfde5cc839e9d11b90a098b8affcf5f6 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/159451 Commit-Queue: Tom Sepez <tsepez@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/formfiller/cffl_formfield.cpp b/fpdfsdk/formfiller/cffl_formfield.cpp index 947fa14..790ad3e 100644 --- a/fpdfsdk/formfiller/cffl_formfield.cpp +++ b/fpdfsdk/formfiller/cffl_formfield.cpp
@@ -12,6 +12,7 @@ #include "core/fpdfapi/page/cpdf_page.h" #include "core/fxcrt/cfx_bidi_resolver.h" #include "core/fxcrt/check.h" +#include "core/fxcrt/observed_ptr.h" #include "core/fxge/cfx_renderdevice.h" #include "fpdfsdk/cpdfsdk_pageview.h" #include "fpdfsdk/cpdfsdk_widget.h" @@ -289,7 +290,12 @@ Mask<FWL_EVENTFLAG> nFlag) { CPDFSDK_PageView* pPageView = form_filler_->GetOrCreatePageView(pWidget->GetPage()); + + ObservedPtr<CFFL_FormField> observed_this(this); CPWL_Wnd* pWnd = CreateOrUpdatePWLWindow(pPageView); + if (!observed_this) { + return; + } if (pWnd) { pWnd->SetFocus(); } @@ -304,7 +310,15 @@ } CPDFSDK_PageView* pPageView = form_filler_->GetPageView(widget_->GetPage()); - if (!pPageView || !CommitData(pPageView, nFlag)) { + if (!pPageView) { + return; + } + + ObservedPtr<CFFL_FormField> observed_this(this); + if (!CommitData(pPageView, nFlag)) { + return; + } + if (!observed_this) { return; } if (CPWL_Wnd* pWnd = GetPWLWindow(pPageView)) { @@ -510,41 +524,40 @@ return true; } - ObservedPtr<CPDFSDK_Widget> pObserved(widget_); - if (!form_filler_->OnKeyStrokeCommit(pObserved, pPageView, nFlag)) { - if (!pObserved) { - return false; - } + ObservedPtr<CFFL_FormField> observed_this(this); + ObservedPtr<CPDFSDK_Widget> observed_widget(widget_); + const bool keystroke_committed = + form_filler_->OnKeyStrokeCommit(observed_widget, pPageView, nFlag); + if (!observed_widget || !observed_this) { + return false; + } + if (!keystroke_committed) { ResetPWLWindow(pPageView); - return true; - } - if (!pObserved) { - return false; + return observed_this.HasObservable(); } - if (!form_filler_->OnValidate(pObserved, pPageView, nFlag)) { - if (!pObserved) { - return false; - } + const bool validated = + form_filler_->OnValidate(observed_widget, pPageView, nFlag); + if (!observed_widget || !observed_this) { + return false; + } + if (!validated) { ResetPWLWindow(pPageView); - return true; + return observed_this.HasObservable(); } - if (!pObserved) { + + SaveData(pPageView); // May invoke JS to delete this widget. + if (!observed_widget || !observed_this) { return false; } - SaveData(pPageView); // may invoking JS to delete this widget. - if (!pObserved) { + form_filler_->OnCalculate(observed_widget); + if (!observed_widget || !observed_this) { return false; } - form_filler_->OnCalculate(pObserved); - if (!pObserved) { - return false; - } - - form_filler_->OnFormat(pObserved); - if (!pObserved) { + form_filler_->OnFormat(observed_widget); + if (!observed_widget || !observed_this) { return false; }
diff --git a/fpdfsdk/formfiller/cffl_textobject.cpp b/fpdfsdk/formfiller/cffl_textobject.cpp index da6cd80..d8743ad 100644 --- a/fpdfsdk/formfiller/cffl_textobject.cpp +++ b/fpdfsdk/formfiller/cffl_textobject.cpp
@@ -8,6 +8,7 @@ #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfdoc/cpdf_bafontmap.h" +#include "core/fxcrt/observed_ptr.h" #include "fpdfsdk/cpdfsdk_widget.h" CFFL_TextObject::CFFL_TextObject(CFFL_InteractiveFormFiller* pFormFiller, @@ -22,18 +23,28 @@ CPWL_Wnd* CFFL_TextObject::ResetPWLWindow(const CPDFSDK_PageView* pPageView) { DestroyPWLWindow(pPageView); - ObservedPtr<CPWL_Wnd> pRet(CreateOrUpdatePWLWindow(pPageView)); - widget_->UpdateField(); // May invoke JS, invalidating |pRet|. - return pRet.Get(); + ObservedPtr<CFFL_FormField> observed_this(this); + ObservedPtr<CPWL_Wnd> observed_wnd(CreateOrUpdatePWLWindow(pPageView)); + if (!observed_this) { + return nullptr; + } + // May invoke JS, invalidating `observed_wnd` and `this`. + widget_->UpdateField(); + return observed_this ? observed_wnd.Get() : nullptr; } CPWL_Wnd* CFFL_TextObject::RestorePWLWindow(const CPDFSDK_PageView* pPageView) { SavePWLWindowState(pPageView); DestroyPWLWindow(pPageView); RecreatePWLWindowFromSavedState(pPageView); - ObservedPtr<CPWL_Wnd> pRet(GetPWLWindow(pPageView)); - widget_->UpdateField(); // May invoke JS, invalidating |pRet|. - return pRet.Get(); + ObservedPtr<CFFL_FormField> observed_this(this); + ObservedPtr<CPWL_Wnd> observed_wnd(GetPWLWindow(pPageView)); + if (!observed_this) { + return nullptr; + } + // May invoke JS, invalidating `observed_wnd` and `this`. + widget_->UpdateField(); + return observed_this ? observed_wnd.Get() : nullptr; } CPDF_BAFontMap* CFFL_TextObject::GetOrCreateFontMap() {