Merge to XFA: Fix stack exhaustion in CPDF_DataAvail::HaveResourceAncestor()
authorTom Sepez <tsepez@chromium.org>
Wed, 4 Feb 2015 00:24:43 +0000 (16:24 -0800)
committerTom Sepez <tsepez@chromium.org>
Wed, 4 Feb 2015 00:24:43 +0000 (16:24 -0800)
Original Review URL: https://codereview.chromium.org/880043004
TBR=thestig@chromium.org

Review URL: https://codereview.chromium.org/893333003

core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
fpdfsdk/src/fpdfview_embeddertest.cpp
testing/resources/bug_113.in [new file with mode: 0644]
testing/resources/bug_113.pdf [new file with mode: 0644]

index 53ee762..c95e616 100644 (file)
@@ -2747,7 +2747,11 @@ public:
     }
 
     virtual void                        GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize)  FX_OVERRIDE;
+
 protected:
+    static const int kMaxDataAvailRecursionDepth = 64;
+    static int s_CurrentDataAvailRecursionDepth;
+
     FX_DWORD                            GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
     FX_BOOL                             IsObjectsAvail(CFX_PtrArray& obj_array, FX_BOOL bParsePage, IFX_DownloadHints* pHints, CFX_PtrArray &ret_array);
     FX_BOOL                             CheckDocStatus(IFX_DownloadHints *pHints);
@@ -2923,6 +2927,9 @@ IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail, IFX_FileRead*
   return FX_NEW CPDF_DataAvail(pFileAvail, pFileRead);
 }
 
+// static
+int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0;
+
 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead)
     : IPDF_DataAvail(pFileAvail, pFileRead)
 {
@@ -4399,6 +4406,10 @@ FX_BOOL CPDF_DataAvail::CheckLinearizedFirstPage(FX_INT32 iPage, IFX_DownloadHin
 }
 FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary *pDict)
 {
+    CFX_AutoRestorer<int> restorer(&s_CurrentDataAvailRecursionDepth);
+    if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) {
+        return FALSE;
+    }
     CPDF_Object *pParent = pDict->GetElement("Parent");
     if (!pParent) {
         return FALSE;
@@ -4411,9 +4422,8 @@ FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary *pDict)
     if (pRet) {
         m_pPageResource = pRet;
         return TRUE;
-    } else {
-        return HaveResourceAncestor(pParentDict);
     }
+    return HaveResourceAncestor(pParentDict);
 }
 FX_BOOL CPDF_DataAvail::IsPageAvail(FX_INT32 iPage, IFX_DownloadHints* pHints)
 {
index 083925f..8a9020a 100644 (file)
@@ -177,12 +177,16 @@ TEST_F(FPDFViewEmbeddertest, NamedDestsByName) {
 }
 
 // The following tests pass if the document opens without crashing.
-TEST_F(FPDFViewEmbeddertest, Crasher1) {
+TEST_F(FPDFViewEmbeddertest, Crasher_113) {
+  EXPECT_TRUE(OpenDocument("testing/resources/bug_113.pdf"));
+}
+
+TEST_F(FPDFViewEmbeddertest, Crasher_451830) {
   // XFA branch detects this document as bad.
   EXPECT_FALSE(OpenDocument("testing/resources/bug_451830.pdf"));
 }
 
-TEST_F(FPDFViewEmbeddertest, Crasher2) {
+TEST_F(FPDFViewEmbeddertest, Crasher_452455) {
   EXPECT_TRUE(OpenDocument("testing/resources/bug_452455.pdf"));
   FPDF_PAGE page = LoadPage(0);
   EXPECT_NE(nullptr, page);
diff --git a/testing/resources/bug_113.in b/testing/resources/bug_113.in
new file mode 100644 (file)
index 0000000..5fc6e71
--- /dev/null
@@ -0,0 +1,29 @@
+{{header}}
+{{object 3 0}} <<
+  /Pages 5 0 R
+>>
+endobj
+{{object 4 0}} <<
+/Type /Page
+/Parent 5 0 R
+/Resources <<
+/Font <<xt
+endobj
+% partial object
+{{object 5 0}} <<
+  /Type /Page
+  /Parent 5 0 R
+  /bork <<
+endobj
+% duplicate definition of partial object
+{{object 5 0}} <<
+  /Kids [4 0 R]
+  /bork 1P
+  /MediaBox [ 0
+endobj
+{{xref}}
+trailer <<
+  /Root 3 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/bug_113.pdf b/testing/resources/bug_113.pdf
new file mode 100644 (file)
index 0000000..0a524c1
--- /dev/null
@@ -0,0 +1,38 @@
+%PDF-1.7
+% ò¤ô
+3 0 obj <<
+  /Pages 5 0 R
+>>
+endobj
+4 0 obj <<
+/Type /Page
+/Parent 5 0 R
+/Resources <<
+/Font <<xt
+endobj
+% partial object
+5 0 obj <<
+  /Type /Page
+  /Parent 5 0 R
+  /bork <<
+endobj
+% duplicate definition of partial object
+5 0 obj <<
+  /Kids [4 0 R]
+  /bork 1P
+  /MediaBox [ 0
+endobj
+xref
+0 6
+0000000000 65536 f
+0000000000 65536 f
+0000000000 65536 f
+0000000015 00000 n
+0000000051 00000 n
+0000000237 00000 n
+trailer <<
+  /Root 3 0 R
+>>
+startxref
+298
+%%EOF