Move parts of PDFFuzzerPublic to a separate target.

Move the relevant parts of PDFFuzzerPublic to a new ProcessState class
in a separate fuzzer_process_state target. Unlike the fuzzer_init_public
target, which must be marked testonly, fuzzer_init_public is only marked
testonly in non-component builds. Thus it can be a dependency for fuzzer
implementations. Set up the proper dependencies to fuzzer_process_state,
and remove workarounds for linker issues in component builds.

The remainder of PDFFuzzerPublic gets merged back into
PDFFuzzerInitPublic.

Change-Id: I7e4049d520d272e4eca58885cfe5e8769fc39d82
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73670
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/testing/fuzzers/BUILD.gn b/testing/fuzzers/BUILD.gn
index 854b51d..81f5100 100644
--- a/testing/fuzzers/BUILD.gn
+++ b/testing/fuzzers/BUILD.gn
@@ -86,6 +86,22 @@
   deps = [ "../../:pdfium_public_headers" ]
 }
 
+if (pdf_enable_xfa) {
+  assert(pdf_enable_v8)
+  source_set("fuzzer_xfa_process_state") {
+    testonly = !is_component_build
+    sources = [
+      "xfa_process_state.cc",
+      "xfa_process_state.h",
+    ]
+    configs += [ ":fuzzer_config" ]
+    deps = [
+      "../../fxjs:gc",
+      "//v8",
+    ]
+  }
+}
+
 source_set("fuzzer_init_public") {
   testonly = true
   sources = [ "pdf_fuzzer_init_public.cc" ]
@@ -102,7 +118,7 @@
       "//v8:v8_libplatform",
     ]
     if (pdf_enable_xfa) {
-      deps += [ "../../fxjs:gc" ]
+      deps += [ ":fuzzer_xfa_process_state" ]
     }
   }
 }
@@ -113,6 +129,9 @@
     foreach(fuzzer, fuzzer_list) {
       deps += [ ":${fuzzer}_impl" ]
     }
+    if (pdf_enable_xfa) {
+      deps += [ ":fuzzer_xfa_process_state" ]
+    }
   }
 }
 
@@ -143,7 +162,8 @@
 }
 
 template("pdfium_fuzzer") {
-  if (defined(invoker.public_fuzzer) && invoker.public_fuzzer) {
+  is_public = defined(invoker.public_fuzzer) && invoker.public_fuzzer
+  if (is_public) {
     init_dep = ":fuzzer_init_public"
   } else {
     init_dep = ":fuzzer_init"
@@ -198,6 +218,9 @@
         init_dep,
       ]
     }
+    if (is_public && pdf_enable_xfa) {
+      deps += [ ":fuzzer_xfa_process_state" ]
+    }
   }
 }
 
diff --git a/testing/fuzzers/pdf_fm2js_fuzzer.cc b/testing/fuzzers/pdf_fm2js_fuzzer.cc
index fcb2071..26fdfd3 100644
--- a/testing/fuzzers/pdf_fm2js_fuzzer.cc
+++ b/testing/fuzzers/pdf_fm2js_fuzzer.cc
@@ -9,11 +9,11 @@
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_string.h"
 #include "fxjs/xfa/cfxjse_formcalc_context.h"
-#include "testing/fuzzers/pdf_fuzzer_init_public.h"
 #include "testing/fuzzers/pdfium_fuzzer_util.h"
+#include "testing/fuzzers/xfa_process_state.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  auto* state = static_cast<PDFFuzzerPublic*>(FPDF_GetFuzzerPerProcessState());
+  auto* state = static_cast<XFAProcessState*>(FPDF_GetFuzzerPerProcessState());
   WideString input = WideString::FromUTF8(ByteStringView(data, size));
   CFXJSE_FormCalcContext::Translate(state->GetHeap(), input.AsStringView());
   state->MaybeForceGCAndPump();
diff --git a/testing/fuzzers/pdf_formcalc_fuzzer.cc b/testing/fuzzers/pdf_formcalc_fuzzer.cc
index 8e73d13..d116648 100644
--- a/testing/fuzzers/pdf_formcalc_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_fuzzer.cc
@@ -4,13 +4,13 @@
 
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_string.h"
-#include "testing/fuzzers/pdf_fuzzer_init_public.h"
 #include "testing/fuzzers/pdfium_fuzzer_util.h"
+#include "testing/fuzzers/xfa_process_state.h"
 #include "third_party/base/logging.h"
 #include "xfa/fxfa/fm2js/cxfa_fmparser.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  auto* state = static_cast<PDFFuzzerPublic*>(FPDF_GetFuzzerPerProcessState());
+  auto* state = static_cast<XFAProcessState*>(FPDF_GetFuzzerPerProcessState());
   WideString input = WideString::FromUTF8(ByteStringView(data, size));
   CXFA_FMParser parser(state->GetHeap(), input.AsStringView());
   parser.Parse();
diff --git a/testing/fuzzers/pdf_fuzzer_init_public.cc b/testing/fuzzers/pdf_fuzzer_init_public.cc
index 002ffa0..eabd2d3 100644
--- a/testing/fuzzers/pdf_fuzzer_init_public.cc
+++ b/testing/fuzzers/pdf_fuzzer_init_public.cc
@@ -11,6 +11,9 @@
 #ifdef PDF_ENABLE_V8
 #include "testing/free_deleter.h"
 #include "testing/v8_initializer.h"
+#ifdef PDF_ENABLE_XFA
+#include "testing/fuzzers/xfa_process_state.h"
+#endif  // PDF_ENABLE_XFA
 #endif  // PDF_ENABLE_V8
 
 #ifdef _WIN32
@@ -57,7 +60,7 @@
 
 }  // namespace
 
-PDFFuzzerPublic::PDFFuzzerPublic() {
+PDFFuzzerInitPublic::PDFFuzzerInitPublic() {
 #ifdef PDF_ENABLE_V8
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   platform_ = InitializeV8ForPDFiumWithStartupData(
@@ -71,7 +74,6 @@
   create_params.array_buffer_allocator = allocator_.get();
   isolate_.reset(v8::Isolate::New(create_params));
   FXGC_Initialize(platform_.get(), isolate_.get());
-  heap_ = FXGC_CreateHeap();
 #endif  // PDF_ENABLE_XFA
 #endif  // PDF_ENABLE_V8
 
@@ -91,30 +93,12 @@
   unsupport_info_.version = 1;
   unsupport_info_.FSDK_UnSupport_Handler = [](UNSUPPORT_INFO*, int) {};
   FSDK_SetUnSpObjProcessHandler(&unsupport_info_);
-}
 
-#ifdef PDF_ENABLE_V8
 #ifdef PDF_ENABLE_XFA
-cppgc::Heap* PDFFuzzerPublic::GetHeap() const {
-  return heap_.get();
-}
-
-void PDFFuzzerPublic::MaybeForceGCAndPump() {
-  if (++iterations_ > 1000) {
-    FXGC_ForceGarbageCollection(heap_.get());
-    iterations_ = 0;
-  }
-  while (v8::platform::PumpMessageLoop(platform_.get(), isolate_.get()))
-    continue;
-}
-#endif  // PDF_ENABLE_XFA
-#endif  // PDF_ENABLE_V8
-
-PDFFuzzerPublic::~PDFFuzzerPublic() = default;
-
-PDFFuzzerInitPublic::PDFFuzzerInitPublic()
-    : context_(std::make_unique<PDFFuzzerPublic>()) {
-  FPDF_SetFuzzerPerProcessState(context_.get());
+  xfa_process_state_ =
+      std::make_unique<XFAProcessState>(platform_.get(), isolate_.get());
+  FPDF_SetFuzzerPerProcessState(xfa_process_state_.get());
+#endif
 }
 
 PDFFuzzerInitPublic::~PDFFuzzerInitPublic() {
diff --git a/testing/fuzzers/pdf_fuzzer_init_public.h b/testing/fuzzers/pdf_fuzzer_init_public.h
index 7711548..93690bb 100644
--- a/testing/fuzzers/pdf_fuzzer_init_public.h
+++ b/testing/fuzzers/pdf_fuzzer_init_public.h
@@ -14,25 +14,15 @@
 #include "fxjs/cfx_v8.h"
 #include "v8/include/v8-platform.h"
 #include "v8/include/v8.h"
-#ifdef PDF_ENABLE_XFA
-#include "fxjs/gc/heap.h"
-#endif  // PDF_ENABLE_XFA
 #endif  // PDF_ENABLE_V8
 
-// Context for all runs of the fuzzer.
-class PDFFuzzerPublic {
+class XFAProcessState;
+
+// Initializes the library once for all runs of the fuzzer.
+class PDFFuzzerInitPublic {
  public:
-  PDFFuzzerPublic();
-  virtual ~PDFFuzzerPublic();
-
-#ifdef PDF_ENABLE_V8
-#ifdef PDF_ENABLE_XFA
-  // Virtualize to avoid linker issues in component builds. This results
-  // in an indirect function callback to code in a higher layer.
-  virtual cppgc::Heap* GetHeap() const;
-  virtual void MaybeForceGCAndPump();
-#endif  // PDF_ENABLE_XFA
-#endif  // PDF_ENABLE_V8
+  PDFFuzzerInitPublic();
+  ~PDFFuzzerInitPublic();
 
  private:
   FPDF_LIBRARY_CONFIG config_;
@@ -43,20 +33,9 @@
   std::unique_ptr<v8::ArrayBuffer::Allocator> allocator_;
   std::unique_ptr<v8::Isolate, CFX_V8IsolateDeleter> isolate_;
 #ifdef PDF_ENABLE_XFA
-  uint32_t iterations_ = 0;
-  FXGCScopedHeap heap_;
+  std::unique_ptr<XFAProcessState> xfa_process_state_;
 #endif  // PDF_ENABLE_XFA
 #endif  // PDF_ENABLE_V8
 };
 
-// Initializes the library once for all runs of the fuzzer.
-class PDFFuzzerInitPublic {
- public:
-  PDFFuzzerInitPublic();
-  ~PDFFuzzerInitPublic();
-
- private:
-  std::unique_ptr<PDFFuzzerPublic> context_;
-};
-
 #endif  // TESTING_FUZZERS_PDF_FUZZER_INIT_PUBLIC_H_
diff --git a/testing/fuzzers/xfa_process_state.cc b/testing/fuzzers/xfa_process_state.cc
new file mode 100644
index 0000000..0a8cf52
--- /dev/null
+++ b/testing/fuzzers/xfa_process_state.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/fuzzers/xfa_process_state.h"
+
+XFAProcessState::XFAProcessState(v8::Platform* platform, v8::Isolate* isolate)
+    : platform_(platform), isolate_(isolate) {}
+
+XFAProcessState::~XFAProcessState() = default;
+
+cppgc::Heap* XFAProcessState::GetHeap() const {
+  return heap_.get();
+}
+
+void XFAProcessState::MaybeForceGCAndPump() {
+  if (++iterations_ > 1000) {
+    FXGC_ForceGarbageCollection(heap_.get());
+    iterations_ = 0;
+  }
+  while (v8::platform::PumpMessageLoop(platform_, isolate_))
+    continue;
+}
diff --git a/testing/fuzzers/xfa_process_state.h b/testing/fuzzers/xfa_process_state.h
new file mode 100644
index 0000000..2636511
--- /dev/null
+++ b/testing/fuzzers/xfa_process_state.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_FUZZERS_XFA_PROCESS_STATE_H_
+#define TESTING_FUZZERS_XFA_PROCESS_STATE_H_
+
+#if !defined(PDF_ENABLE_XFA)
+#error "XFA only"
+#endif
+
+#include "fxjs/gc/heap.h"
+
+namespace v8 {
+class Isolate;
+class Platform;
+}  // namespace v8
+
+class XFAProcessState {
+ public:
+  XFAProcessState(v8::Platform* platform, v8::Isolate* isolate);
+  ~XFAProcessState();
+
+  cppgc::Heap* GetHeap() const;
+  void MaybeForceGCAndPump();
+
+ private:
+  v8::Platform* const platform_;
+  v8::Isolate* const isolate_;
+  int iterations_ = 0;
+  FXGCScopedHeap heap_;
+};
+
+#endif  // TESTING_FUZZERS_XFA_PROCESS_STATE_H_