Add llvm fuzzer for CPDF_PSEngine

Put class definition into its own header file so fuzzer can find it.

Fix a pair of div by 0s immediately hit by the fuzzer.

Review-Url: https://codereview.chromium.org/2253193003
diff --git a/core/fpdfapi/fpdf_page/cpdf_psengine.h b/core/fpdfapi/fpdf_page/cpdf_psengine.h
new file mode 100644
index 0000000..fc8badb
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/cpdf_psengine.h
@@ -0,0 +1,100 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FPDFAPI_FPDF_PAGE_CPDF_PSENGINE_H_
+#define CORE_FPDFAPI_FPDF_PAGE_CPDF_PSENGINE_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/include/fx_system.h"
+
+class CPDF_PSEngine;
+class CPDF_PSOP;
+class CPDF_SimpleParser;
+
+enum PDF_PSOP {
+  PSOP_ADD,
+  PSOP_SUB,
+  PSOP_MUL,
+  PSOP_DIV,
+  PSOP_IDIV,
+  PSOP_MOD,
+  PSOP_NEG,
+  PSOP_ABS,
+  PSOP_CEILING,
+  PSOP_FLOOR,
+  PSOP_ROUND,
+  PSOP_TRUNCATE,
+  PSOP_SQRT,
+  PSOP_SIN,
+  PSOP_COS,
+  PSOP_ATAN,
+  PSOP_EXP,
+  PSOP_LN,
+  PSOP_LOG,
+  PSOP_CVI,
+  PSOP_CVR,
+  PSOP_EQ,
+  PSOP_NE,
+  PSOP_GT,
+  PSOP_GE,
+  PSOP_LT,
+  PSOP_LE,
+  PSOP_AND,
+  PSOP_OR,
+  PSOP_XOR,
+  PSOP_NOT,
+  PSOP_BITSHIFT,
+  PSOP_TRUE,
+  PSOP_FALSE,
+  PSOP_IF,
+  PSOP_IFELSE,
+  PSOP_POP,
+  PSOP_EXCH,
+  PSOP_DUP,
+  PSOP_COPY,
+  PSOP_INDEX,
+  PSOP_ROLL,
+  PSOP_PROC,
+  PSOP_CONST
+};
+
+constexpr uint32_t PSENGINE_STACKSIZE = 100;
+
+class CPDF_PSProc {
+ public:
+  CPDF_PSProc();
+  ~CPDF_PSProc();
+
+  FX_BOOL Parse(CPDF_SimpleParser* parser);
+  FX_BOOL Execute(CPDF_PSEngine* pEngine);
+
+ private:
+  std::vector<std::unique_ptr<CPDF_PSOP>> m_Operators;
+};
+
+class CPDF_PSEngine {
+ public:
+  CPDF_PSEngine();
+  ~CPDF_PSEngine();
+
+  FX_BOOL Parse(const FX_CHAR* str, int size);
+  FX_BOOL Execute();
+  FX_BOOL DoOperator(PDF_PSOP op);
+  void Reset() { m_StackCount = 0; }
+  void Push(FX_FLOAT value);
+  void Push(int value) { Push((FX_FLOAT)value); }
+  FX_FLOAT Pop();
+  uint32_t GetStackSize() const { return m_StackCount; }
+
+ private:
+  FX_FLOAT m_Stack[PSENGINE_STACKSIZE];
+  uint32_t m_StackCount;
+  CPDF_PSProc m_MainProc;
+};
+
+#endif  // CORE_FPDFAPI_FPDF_PAGE_CPDF_PSENGINE_H_
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_func.cpp b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
index ed8e609..6a5bbac 100644
--- a/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
+++ b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "core/fpdfapi/fpdf_page/cpdf_psengine.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h"
@@ -21,58 +22,6 @@
 #include "core/fxcrt/include/fx_safe_types.h"
 #include "third_party/base/numerics/safe_conversions_impl.h"
 
-namespace {
-
-enum PDF_PSOP {
-  PSOP_ADD,
-  PSOP_SUB,
-  PSOP_MUL,
-  PSOP_DIV,
-  PSOP_IDIV,
-  PSOP_MOD,
-  PSOP_NEG,
-  PSOP_ABS,
-  PSOP_CEILING,
-  PSOP_FLOOR,
-  PSOP_ROUND,
-  PSOP_TRUNCATE,
-  PSOP_SQRT,
-  PSOP_SIN,
-  PSOP_COS,
-  PSOP_ATAN,
-  PSOP_EXP,
-  PSOP_LN,
-  PSOP_LOG,
-  PSOP_CVI,
-  PSOP_CVR,
-  PSOP_EQ,
-  PSOP_NE,
-  PSOP_GT,
-  PSOP_GE,
-  PSOP_LT,
-  PSOP_LE,
-  PSOP_AND,
-  PSOP_OR,
-  PSOP_XOR,
-  PSOP_NOT,
-  PSOP_BITSHIFT,
-  PSOP_TRUE,
-  PSOP_FALSE,
-  PSOP_IF,
-  PSOP_IFELSE,
-  PSOP_POP,
-  PSOP_EXCH,
-  PSOP_DUP,
-  PSOP_COPY,
-  PSOP_INDEX,
-  PSOP_ROLL,
-  PSOP_PROC,
-  PSOP_CONST
-};
-
-class CPDF_PSEngine;
-class CPDF_PSProc;
-
 class CPDF_PSOP {
  public:
   explicit CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) {
@@ -105,39 +54,12 @@
   std::unique_ptr<CPDF_PSProc> m_proc;
 };
 
-class CPDF_PSProc {
- public:
-  CPDF_PSProc() {}
-  ~CPDF_PSProc() {}
+FX_BOOL CPDF_PSEngine::Execute() {
+  return m_MainProc.Execute(this);
+}
 
-  FX_BOOL Parse(CPDF_SimpleParser* parser);
-  FX_BOOL Execute(CPDF_PSEngine* pEngine);
-
- private:
-  std::vector<std::unique_ptr<CPDF_PSOP>> m_Operators;
-};
-
-const uint32_t PSENGINE_STACKSIZE = 100;
-
-class CPDF_PSEngine {
- public:
-  CPDF_PSEngine();
-  ~CPDF_PSEngine();
-
-  FX_BOOL Parse(const FX_CHAR* str, int size);
-  FX_BOOL Execute() { return m_MainProc.Execute(this); }
-  FX_BOOL DoOperator(PDF_PSOP op);
-  void Reset() { m_StackCount = 0; }
-  void Push(FX_FLOAT value);
-  void Push(int value) { Push((FX_FLOAT)value); }
-  FX_FLOAT Pop();
-  uint32_t GetStackSize() const { return m_StackCount; }
-
- private:
-  FX_FLOAT m_Stack[PSENGINE_STACKSIZE];
-  uint32_t m_StackCount;
-  CPDF_PSProc m_MainProc;
-};
+CPDF_PSProc::CPDF_PSProc() {}
+CPDF_PSProc::~CPDF_PSProc() {}
 
 FX_BOOL CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) {
   for (size_t i = 0; i < m_Operators.size(); ++i) {
@@ -280,12 +202,12 @@
     case PSOP_IDIV:
       i2 = (int)Pop();
       i1 = (int)Pop();
-      Push(i1 / i2);
+      Push(i2 ? i1 / i2 : 0);
       break;
     case PSOP_MOD:
       i2 = (int)Pop();
       i1 = (int)Pop();
-      Push(i1 % i2);
+      Push(i2 ? i1 % i2 : 0);
       break;
     case PSOP_NEG:
       d1 = Pop();
@@ -538,7 +460,6 @@
   return TRUE;
 }
 
-}  // namespace
 
 CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {}
 
diff --git a/testing/libfuzzer/BUILD.gn b/testing/libfuzzer/BUILD.gn
index 1b7a7fb..718a1db 100644
--- a/testing/libfuzzer/BUILD.gn
+++ b/testing/libfuzzer/BUILD.gn
@@ -168,3 +168,18 @@
     ":libfuzzer_config",
   ]
 }
+
+source_set("pdf_psengine_fuzzer") {
+  testonly = true
+  sources = [
+    "pdf_psengine_fuzzer.cc",
+  ]
+  deps = [
+    "//third_party/pdfium:pdfium",
+  ]
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":libfuzzer_config",
+  ]
+}
diff --git a/testing/libfuzzer/pdf_psengine_fuzzer.cc b/testing/libfuzzer/pdf_psengine_fuzzer.cc
new file mode 100644
index 0000000..89f582e
--- /dev/null
+++ b/testing/libfuzzer/pdf_psengine_fuzzer.cc
@@ -0,0 +1,14 @@
+// Copyright 2016 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 "core/fpdfapi/fpdf_page/cpdf_psengine.h"
+
+#include <cstdint>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  CPDF_PSEngine engine;
+  if (engine.Parse(reinterpret_cast<const char*>(data), size))
+    engine.Execute();
+  return 0;
+}