summaryrefslogtreecommitdiff
path: root/fpdfsdk
diff options
context:
space:
mode:
Diffstat (limited to 'fpdfsdk')
-rw-r--r--fpdfsdk/src/fpdfdoc.cpp25
-rw-r--r--fpdfsdk/src/fpdfdoc_embeddertest.cpp11
2 files changed, 29 insertions, 7 deletions
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 <set>
+
#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<CPDF_Dictionary*>* 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<CPDF_Dictionary*> 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<unsigned short, pdfium::FreeDeleter> title =
+ GetFPDFWideString(L"anything");
+ EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), title.get()));
+}