From 0e2e5d7554af277cfb312294378c2cd862a349d5 Mon Sep 17 00:00:00 2001 From: Wei Li Date: Thu, 3 Mar 2016 11:28:06 -0800 Subject: Fix infinite loop for bookmark search BUG=pdfium:420 R=tsepez@chromium.org Review URL: https://codereview.chromium.org/1757373002 . --- fpdfsdk/src/fpdfdoc.cpp | 25 ++++++++++++++++++------- fpdfsdk/src/fpdfdoc_embeddertest.cpp | 11 +++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) (limited to 'fpdfsdk') diff --git a/fpdfsdk/src/fpdfdoc.cpp b/fpdfsdk/src/fpdfdoc.cpp index 50f3e2c904..4b5da2ffc3 100644 --- a/fpdfsdk/src/fpdfdoc.cpp +++ b/fpdfsdk/src/fpdfdoc.cpp @@ -6,7 +6,10 @@ #include "public/fpdf_doc.h" +#include + #include "fpdfsdk/include/fsdk_define.h" +#include "third_party/base/stl_util.h" namespace { @@ -14,17 +17,24 @@ int THISMODULE = 0; CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree, CPDF_Bookmark bookmark, - const CFX_WideString& title) { + const CFX_WideString& title, + std::set* visited) { + // Return if already checked to avoid circular calling. + if (pdfium::ContainsKey(*visited, bookmark.GetDict())) + return CPDF_Bookmark(); + visited->insert(bookmark.GetDict()); + if (bookmark.GetDict() && bookmark.GetTitle().CompareNoCase(title.c_str()) == 0) { - // First check this item + // First check this item. return bookmark; } - // go into children items + + // Go into children items. CPDF_Bookmark child = tree.GetFirstChild(bookmark); - while (child.GetDict()) { - // check if this item - CPDF_Bookmark found = FindBookmark(tree, child, title); + while (child.GetDict() && !pdfium::ContainsKey(*visited, child.GetDict())) { + // Check this item and its children. + CPDF_Bookmark found = FindBookmark(tree, child, title, visited); if (found.GetDict()) return found; child = tree.GetNextSibling(child); @@ -101,7 +111,8 @@ DLLEXPORT FPDF_BOOKMARK STDCALL FPDFBookmark_Find(FPDF_DOCUMENT document, CPDF_BookmarkTree tree(pDoc); FX_STRSIZE len = CFX_WideString::WStringLength(title); CFX_WideString encodedTitle = CFX_WideString::FromUTF16LE(title, len); - return FindBookmark(tree, CPDF_Bookmark(), encodedTitle).GetDict(); + std::set visited; + return FindBookmark(tree, CPDF_Bookmark(), encodedTitle, &visited).GetDict(); } DLLEXPORT FPDF_DEST STDCALL FPDFBookmark_GetDest(FPDF_DOCUMENT document, diff --git a/fpdfsdk/src/fpdfdoc_embeddertest.cpp b/fpdfsdk/src/fpdfdoc_embeddertest.cpp index a789dade36..0ca6a48ca7 100644 --- a/fpdfsdk/src/fpdfdoc_embeddertest.cpp +++ b/fpdfsdk/src/fpdfdoc_embeddertest.cpp @@ -125,3 +125,14 @@ TEST_F(FPDFDocEmbeddertest, FindBookmarks) { GetFPDFWideString(L"A BAD Beginning"); EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), bad_title.get())); } + +// Check circular bookmarks will not cause infinite loop. +TEST_F(FPDFDocEmbeddertest, FindBookmarks_bug420) { + // Open a file with circular bookmarks. + EXPECT_TRUE(OpenDocument("bookmarks_circular.pdf")); + + // Try to find a title. + std::unique_ptr title = + GetFPDFWideString(L"anything"); + EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), title.get())); +} -- cgit v1.2.3