Watch for destruction of CPDFSDK_widget during callback

Speculative fix since I had trouble with the repro.

BUG=632709

Review-Url: https://codereview.chromium.org/2197793002
diff --git a/fpdfsdk/fsdk_baseform.cpp b/fpdfsdk/fsdk_baseform.cpp
index 287c5cf..1b1d40b 100644
--- a/fpdfsdk/fsdk_baseform.cpp
+++ b/fpdfsdk/fsdk_baseform.cpp
@@ -28,6 +28,7 @@
 #include "fpdfsdk/javascript/ijs_context.h"
 #include "fpdfsdk/javascript/ijs_runtime.h"
 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
+#include "third_party/base/stl_util.h"
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/include/fpdfxfa_doc.h"
@@ -49,6 +50,22 @@
       bFieldFull(FALSE),
       bRC(TRUE) {}
 
+CPDFSDK_Widget::Observer::Observer(CPDFSDK_Widget** pWatchedPtr)
+    : m_pWatchedPtr(pWatchedPtr) {
+  (*m_pWatchedPtr)->AddObserver(this);
+}
+
+CPDFSDK_Widget::Observer::~Observer() {
+  if (m_pWatchedPtr)
+    (*m_pWatchedPtr)->RemoveObserver(this);
+}
+
+void CPDFSDK_Widget::Observer::OnWidgetDestroyed() {
+  ASSERT(m_pWatchedPtr);
+  *m_pWatchedPtr = nullptr;
+  m_pWatchedPtr = nullptr;
+}
+
 CPDFSDK_Widget::CPDFSDK_Widget(CPDF_Annot* pAnnot,
                                CPDFSDK_PageView* pPageView,
                                CPDFSDK_InterForm* pInterForm)
@@ -64,7 +81,20 @@
 {
 }
 
-CPDFSDK_Widget::~CPDFSDK_Widget() {}
+CPDFSDK_Widget::~CPDFSDK_Widget() {
+  for (auto* pObserver : m_Observers)
+    pObserver->OnWidgetDestroyed();
+}
+
+void CPDFSDK_Widget::AddObserver(Observer* pObserver) {
+  ASSERT(!pdfium::ContainsKey(m_Observers, pObserver));
+  m_Observers.insert(pObserver);
+}
+
+void CPDFSDK_Widget::RemoveObserver(Observer* pObserver) {
+  ASSERT(pdfium::ContainsKey(m_Observers, pObserver));
+  m_Observers.erase(pObserver);
+}
 
 #ifdef PDF_ENABLE_XFA
 CXFA_FFWidget* CPDFSDK_Widget::GetMixXFAWidget() const {
diff --git a/fpdfsdk/include/fsdk_baseform.h b/fpdfsdk/include/fsdk_baseform.h
index 91603aa..d386c7f 100644
--- a/fpdfsdk/include/fsdk_baseform.h
+++ b/fpdfsdk/include/fsdk_baseform.h
@@ -8,6 +8,7 @@
 #define FPDFSDK_INCLUDE_FSDK_BASEFORM_H_
 
 #include <map>
+#include <set>
 #include <vector>
 
 #include "core/fpdfdoc/include/ipdf_formnotify.h"
@@ -62,6 +63,17 @@
 
 class CPDFSDK_Widget : public CPDFSDK_BAAnnot {
  public:
+  class Observer {
+   public:
+    explicit Observer(CPDFSDK_Widget** pWatchedPtr);
+    ~Observer();
+
+    void OnWidgetDestroyed();
+
+   private:
+    CPDFSDK_Widget** m_pWatchedPtr;
+  };
+
 #ifdef PDF_ENABLE_XFA
   CXFA_FFWidget* GetMixXFAWidget() const;
   CXFA_FFWidget* GetGroupMixXFAWidget();
@@ -91,6 +103,9 @@
                  CPDFSDK_InterForm* pInterForm);
   ~CPDFSDK_Widget() override;
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   // CPDFSDK_Annot
   CFX_ByteString GetSubType() const override;
   CPDF_Action GetAAction(CPDF_AAction::AActionType eAAT) override;
@@ -172,6 +187,14 @@
   int32_t GetAppearanceAge() const;
   int32_t GetValueAge() const;
 
+  FX_BOOL IsWidgetAppearanceValid(CPDF_Annot::AppearanceMode mode);
+  void DrawAppearance(CFX_RenderDevice* pDevice,
+                      const CFX_Matrix* pUser2Device,
+                      CPDF_Annot::AppearanceMode mode,
+                      const CPDF_RenderOptions* pOptions) override;
+
+  FX_BOOL HitTest(FX_FLOAT pageX, FX_FLOAT pageY);
+
  private:
   void ResetAppearance_PushButton();
   void ResetAppearance_CheckBox();
@@ -194,20 +217,11 @@
   void AddImageToAppearance(const CFX_ByteString& sAPType, CPDF_Stream* pImage);
   void RemoveAppearance(const CFX_ByteString& sAPType);
 
- public:
-  FX_BOOL IsWidgetAppearanceValid(CPDF_Annot::AppearanceMode mode);
-  void DrawAppearance(CFX_RenderDevice* pDevice,
-                      const CFX_Matrix* pUser2Device,
-                      CPDF_Annot::AppearanceMode mode,
-                      const CPDF_RenderOptions* pOptions) override;
-
-  FX_BOOL HitTest(FX_FLOAT pageX, FX_FLOAT pageY);
-
- private:
   CPDFSDK_InterForm* const m_pInterForm;
   FX_BOOL m_bAppModified;
   int32_t m_nAppAge;
   int32_t m_nValueAge;
+  std::set<Observer*> m_Observers;
 
 #ifdef PDF_ENABLE_XFA
   mutable CXFA_FFWidget* m_hMixXFAWidget;
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
index 38309cf..937b3c6 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -229,8 +229,12 @@
     if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_TEXTFIELD) {
       for (CPDFSDK_Widget* pWidget : widgets) {
         FX_BOOL bFormatted = FALSE;
+        CPDFSDK_Widget::Observer observer(&pWidget);
         CFX_WideString sValue = pWidget->OnFormat(bFormatted);
-        pWidget->ResetAppearance(bFormatted ? sValue.c_str() : nullptr, FALSE);
+        if (pWidget) {
+          pWidget->ResetAppearance(bFormatted ? sValue.c_str() : nullptr,
+                                   FALSE);
+        }
       }
     } else {
       for (CPDFSDK_Widget* pWidget : widgets) {