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() {