Commit 3dd27a1dd6c1f05b0931ec47fc430ab60e0a87e7

Authored by m-holger
1 parent 206c2fc1

Detect and warn about outline loops during structure traversal in `--check`. Upd…

…ate tests and adjust exit status accordingly.
libqpdf/QPDFOutlineDocumentHelper.cc
... ... @@ -53,7 +53,11 @@ QPDFOutlineDocumentHelper::validate(bool repair)
53 53 }
54 54 QPDFObjectHandle cur = outlines.getKey("/First");
55 55 QPDFObjGen::set seen;
56   - while (!cur.null() && seen.add(cur)) {
  56 + while (!cur.null()) {
  57 + if (!seen.add(cur)) {
  58 + cur.warn("Loop detected loop in /Outlines tree");
  59 + return;
  60 + }
57 61 m->outlines.emplace_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
58 62 cur = cur.getKey("/Next");
59 63 }
... ...
libqpdf/QPDFOutlineObjectHelper.cc
... ... @@ -20,15 +20,20 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
20 20 return;
21 21 }
22 22 if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) {
  23 + a_oh.warn("Loop detected loop in /Outlines tree");
23 24 return;
24 25 }
25 26  
26 27 QPDFObjGen::set children;
27 28 QPDFObjectHandle cur = a_oh.getKey("/First");
28   - while (!cur.null() && cur.isIndirect() && children.add(cur)) {
  29 + while (!cur.null() && cur.isIndirect()) {
  30 + if (!children.add(cur)) {
  31 + cur.warn("Loop detected loop in /Outlines tree");
  32 + break;
  33 + }
29 34 QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth);
30 35 new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this);
31   - m->kids.push_back(new_ooh);
  36 + m->kids.emplace_back(new_ooh);
32 37 cur = cur.getKey("/Next");
33 38 }
34 39 }
... ...
qpdf/qtest/outlines.test
... ... @@ -32,7 +32,7 @@ foreach my $f (@outline_files)
32 32  
33 33 $td->runtest("outlines: outlines-with-loop --check",
34 34 {$td->COMMAND => "qpdf --check outlines-with-loop.pdf"},
35   - {$td->FILE => "outlines-with-loop-check.out", $td->EXIT_STATUS => 0},
  35 + {$td->FILE => "outlines-with-loop-check.out", $td->EXIT_STATUS => 3},
36 36 $td->NORMALIZE_NEWLINES);
37 37  
38 38 cleanup();
... ...
qpdf/qtest/qpdf/outlines-with-loop-check.out
... ... @@ -2,5 +2,6 @@ checking outlines-with-loop.pdf
2 2 PDF Version: 1.3
3 3 File is not encrypted
4 4 File is not linearized
5   -No syntax or stream encoding errors found; the file may still contain
6   -errors that qpdf cannot detect
  5 +WARNING: outlines-with-loop.pdf, object 4 0 at offset 637: Loop detected loop in /Outlines tree
  6 +WARNING: outlines-with-loop.pdf, object 5 0 at offset 855: Loop detected loop in /Outlines tree
  7 +qpdf: operation succeeded with warnings
... ...
qpdf/qtest/qpdf/outlines-with-loop.out
  1 +WARNING: outlines-with-loop.pdf, object 4 0 at offset 637: Loop detected loop in /Outlines tree
  2 +WARNING: outlines-with-loop.pdf, object 5 0 at offset 855: Loop detected loop in /Outlines tree
1 3 page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ]
2 4 page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ]
3 5 page 11: Mern 1.1 -> 11: /Fit -> [ 17 0 R /Fit ]
... ...