From 8b1e307741d52a0c401296eaf790b18f98d67b6a Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Thu, 19 Sep 2019 20:22:34 -0400 Subject: [PATCH] Warn for duplicated dictionary keys (fixes #345) --- ChangeLog | 7 +++++++ libqpdf/QPDFObjectHandle.cc | 13 ++++++++++++- qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 2 +- qpdf/qtest/qpdf/bad17-recover.out | 1 + qpdf/qtest/qpdf/bad17.out | 1 + qpdf/qtest/qpdf/bad17.pdf | 2 ++ qpdf/qtest/qpdf/issue-51.out | 2 ++ 8 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 29da54b9..5427224e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Jay Berkenbilt + + * Warn when duplicated dictionary keys are found during parsing. + The behavior remains as before: later keys override earlier ones. + However, this generates a warning now rather than being silently + ignored. Fixes #345. + 2019-09-17 Jay Berkenbilt * QIntC tests: don't assume char is signed. Fixes #361. diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index a6d07190..4ee25bc7 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2135,7 +2135,18 @@ QPDFObjectHandle::parseInternal(PointerHolder input, { val = olist.at(++i); } - dict[key_obj.getName()] = val; + std::string key = key_obj.getName(); + if (dict.count(key) > 0) + { + QTC::TC("qpdf", "QPDFObjectHandle duplicate dict key"); + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + input->getName(), object_description, offset, + "dictionary has duplicated key " + key + + "; last occurrence overrides earlier ones")); + } + dict[key] = val; } object = newDictionary(dict); setObjectDescriptionFromInput( diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index f327d464..a34a3f39 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -445,3 +445,4 @@ QPDF eof skipping spaces before xref 1 QPDF_encryption user matches owner V < 5 0 QPDF_encryption same password 1 QPDFWriter stream in ostream 0 +QPDFObjectHandle duplicate dict key 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 460685d9..683700a0 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -2314,7 +2314,7 @@ my @badfiles = ("not a PDF file", # 1 "bad }", # 14 "bad ]", # 15 "bad >>", # 16 - "odd number of dictionary items", # 17 + "dictionary errors", # 17 "bad )", # 18 "bad >", # 19 "invalid hexstring character", # 20 diff --git a/qpdf/qtest/qpdf/bad17-recover.out b/qpdf/qtest/qpdf/bad17-recover.out index 8fed7e43..4fa20e64 100644 --- a/qpdf/qtest/qpdf/bad17-recover.out +++ b/qpdf/qtest/qpdf/bad17-recover.out @@ -1,3 +1,4 @@ +WARNING: bad17.pdf (trailer, offset 715): dictionary has duplicated key /K; last occurrence overrides earlier ones WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key /QTest is implicit /QTest is direct and has type null (2) diff --git a/qpdf/qtest/qpdf/bad17.out b/qpdf/qtest/qpdf/bad17.out index 189daef2..85501992 100644 --- a/qpdf/qtest/qpdf/bad17.out +++ b/qpdf/qtest/qpdf/bad17.out @@ -1,3 +1,4 @@ +WARNING: bad17.pdf (trailer, offset 715): dictionary has duplicated key /K; last occurrence overrides earlier ones WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key /QTest is implicit /QTest is direct and has type null (2) diff --git a/qpdf/qtest/qpdf/bad17.pdf b/qpdf/qtest/qpdf/bad17.pdf index 5afb00d2..ee2f01aa 100644 --- a/qpdf/qtest/qpdf/bad17.pdf +++ b/qpdf/qtest/qpdf/bad17.pdf @@ -73,6 +73,8 @@ xref trailer << /Size 7 /Root 1 0 R + /K 1 + /K 2 /Something >> startxref diff --git a/qpdf/qtest/qpdf/issue-51.out b/qpdf/qtest/qpdf/issue-51.out index 518ab7cf..b4bd165c 100644 --- a/qpdf/qtest/qpdf/issue-51.out +++ b/qpdf/qtest/qpdf/issue-51.out @@ -1,6 +1,8 @@ WARNING: issue-51.pdf: can't find PDF header WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) +WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj +WARNING: issue-51.pdf (object 1 0, offset 236): dictionary has duplicated key /00000000; last occurrence overrides earlier ones WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0 WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary is not an integer