Fix hint table loading issues.

BUG=566179
R=jun_fang@foxitsoftware.com, thestig@chromium.org

Review URL: https://codereview.chromium.org/1523523002 .
diff --git a/core/include/fxcrt/fx_basic.h b/core/include/fxcrt/fx_basic.h
index c5bb570..5d3fc33 100644
--- a/core/include/fxcrt/fx_basic.h
+++ b/core/include/fxcrt/fx_basic.h
@@ -811,6 +811,12 @@
 
   void Rewind() { m_BitPos = 0; }
 
+  FX_DWORD GetPos() { return m_BitPos; }
+
+  FX_DWORD BitsRemaining() {
+    return m_BitSize >= m_BitPos ? m_BitSize - m_BitPos : 0;
+  }
+
  protected:
   FX_DWORD m_BitPos;
 
diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
index 61d9749..db9e177 100644
--- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
+++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
@@ -4643,12 +4643,16 @@
   return szArray[index + 1] - szArray[index];
 }
 FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) {
-  if (!hStream)
+  if (!hStream || hStream->IsEOF())
     return FALSE;
   int nStreamOffset = ReadPrimaryHintStreamOffset();
   int nStreamLen = ReadPrimaryHintStreamLength();
   if (nStreamOffset < 0 || nStreamLen < 1)
     return FALSE;
+
+  const FX_DWORD kHeaderSize = 288;
+  if (hStream->BitsRemaining() < kHeaderSize)
+    return FALSE;
   // Item 1: The least number of objects in a page.
   FX_DWORD dwObjLeastNum = hStream->GetBits(32);
   // Item 2: The location of the first page's page object.
@@ -4691,6 +4695,11 @@
   int nPages = pPageNum ? pPageNum->GetInteger() : 0;
   if (nPages < 1)
     return FALSE;
+  FX_SAFE_DWORD required_bits = dwDeltaObjectsBits;
+  required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages);
+  if (!required_bits.IsValid() ||
+      hStream->BitsRemaining() < required_bits.ValueOrDie())
+    return FALSE;
   for (int i = 0; i < nPages; ++i) {
     FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits);
     safeDeltaObj += dwObjLeastNum;
@@ -4699,6 +4708,11 @@
     m_dwDeltaNObjsArray.Add(safeDeltaObj.ValueOrDie());
   }
   hStream->ByteAlign();
+  required_bits = dwDeltaPageLenBits;
+  required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages);
+  if (!required_bits.IsValid() ||
+      hStream->BitsRemaining() < required_bits.ValueOrDie())
+    return FALSE;
   CFX_DWordArray dwPageLenArray;
   for (int i = 0; i < nPages; ++i) {
     FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits);
@@ -4739,12 +4753,22 @@
   }
   hStream->ByteAlign();
   // number of shared objects
+  required_bits = dwSharedObjBits;
+  required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages);
+  if (!required_bits.IsValid() ||
+      hStream->BitsRemaining() < required_bits.ValueOrDie())
+    return FALSE;
   for (int i = 0; i < nPages; i++) {
     m_dwNSharedObjsArray.Add(hStream->GetBits(dwSharedObjBits));
   }
   hStream->ByteAlign();
   // array of identifier, sizes = nshared_objects
   for (int i = 0; i < nPages; i++) {
+    required_bits = dwSharedIdBits;
+    required_bits *= m_dwNSharedObjsArray[i];
+    if (!required_bits.IsValid() ||
+        hStream->BitsRemaining() < required_bits.ValueOrDie())
+      return FALSE;
     for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) {
       m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits));
     }
@@ -4753,26 +4777,38 @@
   for (int i = 0; i < nPages; i++) {
     FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i];
     safeSize *= dwSharedNumeratorBits;
-    if (!safeSize.IsValid())
+    if (!safeSize.IsValid() || hStream->BitsRemaining() < safeSize.ValueOrDie())
       return FALSE;
     hStream->SkipBits(safeSize.ValueOrDie());
   }
   hStream->ByteAlign();
   FX_SAFE_DWORD safeTotalPageLen = pdfium::base::checked_cast<FX_DWORD>(nPages);
   safeTotalPageLen *= dwDeltaPageLenBits;
-  if (!safeTotalPageLen.IsValid())
+  if (!safeTotalPageLen.IsValid() ||
+      hStream->BitsRemaining() < safeTotalPageLen.ValueOrDie())
     return FALSE;
   hStream->SkipBits(safeTotalPageLen.ValueOrDie());
   hStream->ByteAlign();
   return TRUE;
 }
-FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream) {
-  if (!hStream)
+FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream,
+                                                FX_DWORD offset) {
+  if (!hStream || hStream->IsEOF())
     return FALSE;
   int nStreamOffset = ReadPrimaryHintStreamOffset();
   int nStreamLen = ReadPrimaryHintStreamLength();
   if (nStreamOffset < 0 || nStreamLen < 1)
     return FALSE;
+
+  FX_SAFE_DWORD bit_offset = offset;
+  bit_offset *= 8;
+  if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie())
+    return FALSE;
+  hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos());
+
+  const FX_DWORD kHeaderSize = 192;
+  if (hStream->BitsRemaining() < kHeaderSize)
+    return FALSE;
   // Item 1: The object number of the first object in the shared objects
   // section.
   FX_DWORD dwFirstSharedObjNum = hStream->GetBits(32);
@@ -4800,6 +4836,12 @@
     return FALSE;
   FX_DWORD dwPrevObjLen = 0;
   FX_DWORD dwCurObjLen = 0;
+  FX_SAFE_DWORD required_bits = dwSharedObjTotal;
+  required_bits *= dwDeltaGroupLen;
+  if (!required_bits.IsValid() ||
+      hStream->BitsRemaining() < required_bits.ValueOrDie())
+    return FALSE;
+
   for (int i = 0; i < dwSharedObjTotal; ++i) {
     dwPrevObjLen = dwCurObjLen;
     FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen);
@@ -4837,6 +4879,8 @@
     m_szSharedObjOffsetArray.Add(safeLoc.ValueOrDie());
   }
   hStream->ByteAlign();
+  if (hStream->BitsRemaining() < dwSharedObjTotal)
+    return FALSE;
   hStream->SkipBits(dwSharedObjTotal);
   hStream->ByteAlign();
   return TRUE;
@@ -4898,6 +4942,8 @@
   FX_DWORD dwObjNum = 0;
   for (int j = 0; j < m_dwNSharedObjsArray[index]; ++j) {
     dwIndex = m_dwIdentifierArray[offset + j];
+    if (dwIndex >= m_dwSharedObjNumArray.GetSize())
+      return IPDF_DataAvail::DataNotAvailable;
     dwObjNum = m_dwSharedObjNumArray[dwIndex];
     if (dwObjNum >= nFirstPageObjNum &&
         dwObjNum < nFirstPageObjNum + m_nFirstPageSharedObjs) {
@@ -4919,6 +4965,7 @@
   CPDF_Object* pOffset = pDict ? pDict->GetElement(FX_BSTRC("S")) : nullptr;
   if (!pOffset || pOffset->GetType() != PDFOBJ_NUMBER)
     return FALSE;
+  int shared_hint_table_offset = pOffset->GetInteger();
   CPDF_StreamAcc acc;
   acc.LoadAllData(pHintStream);
   FX_DWORD size = acc.GetSize();
@@ -4926,13 +4973,15 @@
   // The header section of shared object hint table is 24 bytes.
   // Hint table has at least 60 bytes.
   const FX_DWORD MIN_STREAM_LEN = 60;
-  if (size < MIN_STREAM_LEN || size < pOffset->GetInteger() ||
-      !pOffset->GetInteger()) {
+  if (size < MIN_STREAM_LEN || shared_hint_table_offset < 0 ||
+      size < shared_hint_table_offset || !shared_hint_table_offset) {
     return FALSE;
   }
   CFX_BitStream bs;
   bs.Init(acc.GetData(), size);
-  return ReadPageHintTable(&bs) && ReadSharedObjHintTable(&bs);
+  return ReadPageHintTable(&bs) &&
+         ReadSharedObjHintTable(&bs, pdfium::base::checked_cast<FX_DWORD>(
+                                         shared_hint_table_offset));
 }
 int CPDF_HintTables::ReadPrimaryHintStreamOffset() const {
   if (!m_pLinearizedDict)
diff --git a/core/src/fpdfapi/fpdf_parser/parser_int.h b/core/src/fpdfapi/fpdf_parser/parser_int.h
index fba6663..c7f2403 100644
--- a/core/src/fpdfapi/fpdf_parser/parser_int.h
+++ b/core/src/fpdfapi/fpdf_parser/parser_int.h
@@ -34,7 +34,7 @@
 
  protected:
   FX_BOOL ReadPageHintTable(CFX_BitStream* hStream);
-  FX_BOOL ReadSharedObjHintTable(CFX_BitStream* hStream);
+  FX_BOOL ReadSharedObjHintTable(CFX_BitStream* hStream, FX_DWORD offset);
   FX_DWORD GetItemLength(int index, const CFX_FileSizeArray& szArray);
 
  private: