You need to sign in before continuing.
Commit 8b1e307741d52a0c401296eaf790b18f98d67b6a
1 parent
5ce287d6
Warn for duplicated dictionary keys (fixes #345)
Showing
8 changed files
with
27 additions
and
2 deletions
ChangeLog
| 1 | +2019-09-19 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Warn when duplicated dictionary keys are found during parsing. | ||
| 4 | + The behavior remains as before: later keys override earlier ones. | ||
| 5 | + However, this generates a warning now rather than being silently | ||
| 6 | + ignored. Fixes #345. | ||
| 7 | + | ||
| 1 | 2019-09-17 Jay Berkenbilt <ejb@ql.org> | 8 | 2019-09-17 Jay Berkenbilt <ejb@ql.org> |
| 2 | 9 | ||
| 3 | * QIntC tests: don't assume char is signed. Fixes #361. | 10 | * QIntC tests: don't assume char is signed. Fixes #361. |
libqpdf/QPDFObjectHandle.cc
| @@ -2135,7 +2135,18 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, | @@ -2135,7 +2135,18 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, | ||
| 2135 | { | 2135 | { |
| 2136 | val = olist.at(++i); | 2136 | val = olist.at(++i); |
| 2137 | } | 2137 | } |
| 2138 | - dict[key_obj.getName()] = val; | 2138 | + std::string key = key_obj.getName(); |
| 2139 | + if (dict.count(key) > 0) | ||
| 2140 | + { | ||
| 2141 | + QTC::TC("qpdf", "QPDFObjectHandle duplicate dict key"); | ||
| 2142 | + warn(context, | ||
| 2143 | + QPDFExc( | ||
| 2144 | + qpdf_e_damaged_pdf, | ||
| 2145 | + input->getName(), object_description, offset, | ||
| 2146 | + "dictionary has duplicated key " + key + | ||
| 2147 | + "; last occurrence overrides earlier ones")); | ||
| 2148 | + } | ||
| 2149 | + dict[key] = val; | ||
| 2139 | } | 2150 | } |
| 2140 | object = newDictionary(dict); | 2151 | object = newDictionary(dict); |
| 2141 | setObjectDescriptionFromInput( | 2152 | setObjectDescriptionFromInput( |
qpdf/qpdf.testcov
| @@ -445,3 +445,4 @@ QPDF eof skipping spaces before xref 1 | @@ -445,3 +445,4 @@ QPDF eof skipping spaces before xref 1 | ||
| 445 | QPDF_encryption user matches owner V < 5 0 | 445 | QPDF_encryption user matches owner V < 5 0 |
| 446 | QPDF_encryption same password 1 | 446 | QPDF_encryption same password 1 |
| 447 | QPDFWriter stream in ostream 0 | 447 | QPDFWriter stream in ostream 0 |
| 448 | +QPDFObjectHandle duplicate dict key 0 |
qpdf/qtest/qpdf.test
| @@ -2314,7 +2314,7 @@ my @badfiles = ("not a PDF file", # 1 | @@ -2314,7 +2314,7 @@ my @badfiles = ("not a PDF file", # 1 | ||
| 2314 | "bad }", # 14 | 2314 | "bad }", # 14 |
| 2315 | "bad ]", # 15 | 2315 | "bad ]", # 15 |
| 2316 | "bad >>", # 16 | 2316 | "bad >>", # 16 |
| 2317 | - "odd number of dictionary items", # 17 | 2317 | + "dictionary errors", # 17 |
| 2318 | "bad )", # 18 | 2318 | "bad )", # 18 |
| 2319 | "bad >", # 19 | 2319 | "bad >", # 19 |
| 2320 | "invalid hexstring character", # 20 | 2320 | "invalid hexstring character", # 20 |
qpdf/qtest/qpdf/bad17-recover.out
| 1 | +WARNING: bad17.pdf (trailer, offset 715): dictionary has duplicated key /K; last occurrence overrides earlier ones | ||
| 1 | WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key | 2 | WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key |
| 2 | /QTest is implicit | 3 | /QTest is implicit |
| 3 | /QTest is direct and has type null (2) | 4 | /QTest is direct and has type null (2) |
qpdf/qtest/qpdf/bad17.out
| 1 | +WARNING: bad17.pdf (trailer, offset 715): dictionary has duplicated key /K; last occurrence overrides earlier ones | ||
| 1 | WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key | 2 | WARNING: bad17.pdf (trailer, offset 715): dictionary ended prematurely; using null as value for last key |
| 2 | /QTest is implicit | 3 | /QTest is implicit |
| 3 | /QTest is direct and has type null (2) | 4 | /QTest is direct and has type null (2) |
qpdf/qtest/qpdf/bad17.pdf
qpdf/qtest/qpdf/issue-51.out
| 1 | WARNING: issue-51.pdf: can't find PDF header | 1 | WARNING: issue-51.pdf: can't find PDF header |
| 2 | WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) | 2 | WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8) |
| 3 | +WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones | ||
| 3 | WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj | 4 | WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj |
| 5 | +WARNING: issue-51.pdf (object 1 0, offset 236): dictionary has duplicated key /00000000; last occurrence overrides earlier ones | ||
| 4 | WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj | 6 | WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj |
| 5 | WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0 | 7 | WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0 |
| 6 | WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary is not an integer | 8 | WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary is not an integer |