Do not access form_fill_env_ until after last re-entrant JS call.

Follow-on from https://pdfium-review.googlesource.com/c/pdfium/+/147790,
but again this should not be reachable unless an embedder is doing some
unexpected cleanup.

Change-Id: Ibdc3ec6e97e5c5c4fe534ad95778e04050844256
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/147930
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index 0b8e0f9..338d319 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -166,12 +166,15 @@
 
 CJS_Result CJS_Document::set_dirty(CJS_Runtime* pRuntime,
                                    v8::Local<v8::Value> vp) {
+  const bool is_dirty = pRuntime->ToBooleanReentrant(vp);
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
-
-  pRuntime->ToBooleanReentrant(vp) ? form_fill_env_->SetChangeMark()
-                                   : form_fill_env_->ClearChangeMark();
+  if (is_dirty) {
+    form_fill_env_->SetChangeMark();
+  } else {
+    form_fill_env_->ClearChangeMark();
+  }
   return CJS_Result::Success();
 }
 
@@ -199,12 +202,12 @@
 
 CJS_Result CJS_Document::set_page_num(CJS_Runtime* pRuntime,
                                       v8::Local<v8::Value> vp) {
+  int iPageNum = pRuntime->ToInt32Reentrant(vp);
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
 
   int iPageCount = form_fill_env_->GetPageCount();
-  int iPageNum = pRuntime->ToInt32Reentrant(vp);
   if (iPageNum >= 0 && iPageNum < iPageCount) {
     form_fill_env_->JS_docgotoPage(iPageNum);
   } else if (iPageNum >= iPageCount) {
@@ -255,11 +258,11 @@
     return CJS_Result::Failure(JSMessage::kParamError);
   }
 
+  WideString wideName = pRuntime->ToWideStringReentrant(params[0]);
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
 
-  WideString wideName = pRuntime->ToWideStringReentrant(params[0]);
   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
   if (pPDFForm->CountFields(wideName) <= 0) {
     return CJS_Result::Success(pRuntime->NewUndefined());
@@ -288,15 +291,16 @@
   if (params.size() != 1) {
     return CJS_Result::Failure(JSMessage::kParamError);
   }
-  if (!form_fill_env_) {
-    return CJS_Result::Failure(JSMessage::kBadObjectError);
-  }
 
   int nIndex = pRuntime->ToInt32Reentrant(params[0]);
   if (nIndex < 0) {
     return CJS_Result::Failure(JSMessage::kValueError);
   }
 
+  if (!form_fill_env_) {
+    return CJS_Result::Failure(JSMessage::kBadObjectError);
+  }
+
   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
   CPDF_FormField* pField = pPDFForm->GetField(nIndex, WideString());
   if (!pField) {
@@ -329,10 +333,6 @@
 
 CJS_Result CJS_Document::mailDoc(CJS_Runtime* pRuntime,
                                  pdfium::span<v8::Local<v8::Value>> params) {
-  if (!form_fill_env_) {
-    return CJS_Result::Failure(JSMessage::kBadObjectError);
-  }
-
   v8::LocalVector<v8::Value> newParams = ExpandKeywordParams(
       pRuntime, params, 6, "bUI", "cTo", "cCc", "cBcc", "cSubject", "cMsg");
 
@@ -366,6 +366,10 @@
     cMsg = pRuntime->ToWideStringReentrant(newParams[5]);
   }
 
+  if (!form_fill_env_) {
+    return CJS_Result::Failure(JSMessage::kBadObjectError);
+  }
+
   pRuntime->BeginBlock();
   form_fill_env_->JS_docmailForm(pdfium::span<const uint8_t>(), bUI, cTo,
                                  cSubject, cCc, cBcc, cMsg);
@@ -378,21 +382,6 @@
 // comment: need reader supports
 CJS_Result CJS_Document::mailForm(CJS_Runtime* pRuntime,
                                   pdfium::span<v8::Local<v8::Value>> params) {
-  if (!form_fill_env_) {
-    return CJS_Result::Failure(JSMessage::kBadObjectError);
-  }
-
-  using pdfium::access_permissions::kExtractForAccessibility;
-  if (!form_fill_env_->HasPermissions(kExtractForAccessibility)) {
-    return CJS_Result::Failure(JSMessage::kPermissionError);
-  }
-
-  CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
-  ByteString sTextBuf = pInteractiveForm->ExportFormToFDFTextBuf();
-  if (sTextBuf.IsEmpty()) {
-    return CJS_Result::Failure(WideString::FromASCII("Bad FDF format."));
-  }
-
   v8::LocalVector<v8::Value> newParams = ExpandKeywordParams(
       pRuntime, params, 6, "bUI", "cTo", "cCc", "cBcc", "cSubject", "cMsg");
 
@@ -426,6 +415,21 @@
     cMsg = pRuntime->ToWideStringReentrant(newParams[5]);
   }
 
+  if (!form_fill_env_) {
+    return CJS_Result::Failure(JSMessage::kBadObjectError);
+  }
+
+  using pdfium::access_permissions::kExtractForAccessibility;
+  if (!form_fill_env_->HasPermissions(kExtractForAccessibility)) {
+    return CJS_Result::Failure(JSMessage::kPermissionError);
+  }
+
+  CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
+  ByteString sTextBuf = pInteractiveForm->ExportFormToFDFTextBuf();
+  if (sTextBuf.IsEmpty()) {
+    return CJS_Result::Failure(WideString::FromASCII("Bad FDF format."));
+  }
+
   pRuntime->BeginBlock();
   form_fill_env_->JS_docmailForm(sTextBuf.unsigned_span(), bUI, cTo, cSubject,
                                  cCc, cBcc, cMsg);
@@ -502,17 +506,17 @@
   if (params.size() != 1) {
     return CJS_Result::Failure(JSMessage::kParamError);
   }
+  WideString sFieldName = pRuntime->ToWideStringReentrant(params[0]);
+
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
-
   if (!form_fill_env_->HasPermissions(
           pdfium::access_permissions::kModifyContent |
           pdfium::access_permissions::kModifyAnnotation)) {
     return CJS_Result::Failure(JSMessage::kPermissionError);
   }
 
-  WideString sFieldName = pRuntime->ToWideStringReentrant(params[0]);
   CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
   std::vector<ObservedPtr<CPDFSDK_Widget>> widgets;
   pInteractiveForm->GetWidgets(sFieldName, &widgets);
@@ -590,7 +594,9 @@
 
   if (!aFields.empty()) {
     pPDFForm->ResetForm(aFields, true);
-    form_fill_env_->SetChangeMark();
+    if (form_fill_env_) {
+      form_fill_env_->SetChangeMark();
+    }
   }
 
   return CJS_Result::Success();
@@ -614,10 +620,6 @@
   if (nSize < 1) {
     return CJS_Result::Failure(JSMessage::kParamError);
   }
-  if (!form_fill_env_) {
-    return CJS_Result::Failure(JSMessage::kBadObjectError);
-  }
-
   CJS_EventContext* pHandler = pRuntime->GetCurrentEventContext();
   if (!pHandler->IsUserGesture()) {
     return CJS_Result::Failure(JSMessage::kUserGestureRequiredError);
@@ -654,6 +656,10 @@
         pRuntime->GetObjectPropertyReentrant(pObj, "aFields"));
   }
 
+  if (!form_fill_env_) {
+    return CJS_Result::Failure(JSMessage::kBadObjectError);
+  }
+
   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
   if (pRuntime->GetArrayLength(aFields) == 0 && bEmpty) {
     if (pPDFForm->CheckRequiredFields(nullptr, true)) {
@@ -674,7 +680,6 @@
       if (!bEmpty && pField->GetValue().IsEmpty()) {
         continue;
       }
-
       fieldObjects.push_back(pField);
     }
   }
@@ -822,6 +827,8 @@
 
 CJS_Result CJS_Document::set_delay(CJS_Runtime* pRuntime,
                                    v8::Local<v8::Value> vp) {
+  const bool delay = pRuntime->ToBooleanReentrant(vp);
+
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
@@ -831,7 +838,7 @@
     return CJS_Result::Failure(JSMessage::kPermissionError);
   }
 
-  delay_ = pRuntime->ToBooleanReentrant(vp);
+  delay_ = delay;
   if (delay_) {
     delay_data_.clear();
     return CJS_Result::Success();
@@ -1069,12 +1076,14 @@
   if (params.size() != 2) {
     return CJS_Result::Failure(JSMessage::kParamError);
   }
+
+  int nPageNo = pRuntime->ToInt32Reentrant(params[0]);
+  WideString swAnnotName = pRuntime->ToWideStringReentrant(params[1]);
+
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
 
-  int nPageNo = pRuntime->ToInt32Reentrant(params[0]);
-  WideString swAnnotName = pRuntime->ToWideStringReentrant(params[1]);
   CPDFSDK_PageView* pPageView = form_fill_env_->GetPageViewAtIndex(nPageNo);
   if (!pPageView) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
@@ -1308,6 +1317,13 @@
 CJS_Result CJS_Document::getPageNthWord(
     CJS_Runtime* pRuntime,
     pdfium::span<v8::Local<v8::Value>> params) {
+  int nPageNo = params.size() > 0 ? pRuntime->ToInt32Reentrant(params[0]) : 0;
+  int nWordNo = params.size() > 1 ? pRuntime->ToInt32Reentrant(params[1]) : 0;
+  bool bStrip =
+      params.size() > 2 ? pRuntime->ToBooleanReentrant(params[2]) : true;
+
+  // TODO(tsepez): check maximum allowable params.
+
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
@@ -1317,13 +1333,6 @@
     return CJS_Result::Failure(JSMessage::kPermissionError);
   }
 
-  // TODO(tsepez): check maximum allowable params.
-
-  int nPageNo = params.size() > 0 ? pRuntime->ToInt32Reentrant(params[0]) : 0;
-  int nWordNo = params.size() > 1 ? pRuntime->ToInt32Reentrant(params[1]) : 0;
-  bool bStrip =
-      params.size() > 2 ? pRuntime->ToBooleanReentrant(params[2]) : true;
-
   CPDF_Document* document = form_fill_env_->GetPDFDocument();
   if (nPageNo < 0 || nPageNo >= document->GetPageCount()) {
     return CJS_Result::Failure(JSMessage::kValueError);
@@ -1377,6 +1386,8 @@
 CJS_Result CJS_Document::getPageNumWords(
     CJS_Runtime* pRuntime,
     pdfium::span<v8::Local<v8::Value>> params) {
+  int nPageNo = params.size() > 0 ? pRuntime->ToInt32Reentrant(params[0]) : 0;
+
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
@@ -1386,7 +1397,6 @@
     return CJS_Result::Failure(JSMessage::kPermissionError);
   }
 
-  int nPageNo = params.size() > 0 ? pRuntime->ToInt32Reentrant(params[0]) : 0;
   CPDF_Document* document = form_fill_env_->GetPDFDocument();
   if (nPageNo < 0 || nPageNo >= document->GetPageCount()) {
     return CJS_Result::Failure(JSMessage::kValueError);
@@ -1475,14 +1485,15 @@
   if (params.size() != 1) {
     return CJS_Result::Failure(JSMessage::kParamError);
   }
+  const ByteString dest_name = pRuntime->ToByteStringReentrant(params[0]);
 
   if (!form_fill_env_) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
 
   CPDF_Document* document = form_fill_env_->GetPDFDocument();
-  RetainPtr<const CPDF_Array> dest_array = CPDF_NameTree::LookupNamedDest(
-      document, pRuntime->ToByteStringReentrant(params[0]));
+  RetainPtr<const CPDF_Array> dest_array =
+      CPDF_NameTree::LookupNamedDest(document, dest_name);
   if (!dest_array) {
     return CJS_Result::Failure(JSMessage::kBadObjectError);
   }
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index c020254..e8c1658 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -2179,8 +2179,6 @@
 
 CJS_Result CJS_Field::set_text_font(CJS_Runtime* pRuntime,
                                     v8::Local<v8::Value> vp) {
-  DCHECK(form_fill_env_);
-
   if (!can_set_) {
     return CJS_Result::Failure(JSMessage::kReadOnlyError);
   }
diff --git a/fxjs/cjs_publicmethods.cpp b/fxjs/cjs_publicmethods.cpp
index 29349a8..38d7839 100644
--- a/fxjs/cjs_publicmethods.cpp
+++ b/fxjs/cjs_publicmethods.cpp
@@ -1378,8 +1378,12 @@
   v8::Local<v8::Array> FieldNameArray =
       AF_MakeArrayFromList(pRuntime, params[1]);
 
-  CPDFSDK_InteractiveForm* pReaderForm =
-      pRuntime->GetFormFillEnv()->GetInteractiveForm();
+  CPDFSDK_FormFillEnvironment* form_fill_env = pRuntime->GetFormFillEnv();
+  if (!form_fill_env) {
+    return CJS_Result::Failure(JSMessage::kBadObjectError);
+  }
+
+  CPDFSDK_InteractiveForm* pReaderForm = form_fill_env->GetInteractiveForm();
   CPDF_InteractiveForm* pForm = pReaderForm->GetInteractiveForm();
 
   double dValue = sFunction.EqualsASCII("PRD") ? 1.0 : 0.0;