Commit ff42ea4e6cb8b03badf31993fcb4d9f57bb2ad1e
Committed by
Jay Berkenbilt
1 parent
1d9209ee
Fix logic for fixDanglingReferences
Showing
3 changed files
with
33 additions
and
40 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -1292,48 +1292,48 @@ QPDF::showXRefTable() |
| 1292 | 1292 | } |
| 1293 | 1293 | } |
| 1294 | 1294 | |
| 1295 | -// Ensure all objects in the pdf file, including those in indirect references, | |
| 1296 | -// appear in the object cache. | |
| 1297 | 1295 | void |
| 1298 | 1296 | QPDF::fixDanglingReferences(bool force) |
| 1299 | 1297 | { |
| 1298 | + // Ensure all objects in the pdf file, including those in indirect | |
| 1299 | + // references, appear in the object cache. | |
| 1300 | 1300 | if (this->m->fixed_dangling_refs && !force) { |
| 1301 | 1301 | return; |
| 1302 | 1302 | } |
| 1303 | 1303 | |
| 1304 | - if (!this->m->fixed_dangling_refs) { | |
| 1305 | - // First pass is only run if the the xref table has not been | |
| 1306 | - // reconstructed. It will be terminated as soon as reconstruction is | |
| 1307 | - // triggered. | |
| 1308 | - if (!this->m->reconstructed_xref) { | |
| 1309 | - for (auto const& iter: this->m->xref_table) { | |
| 1310 | - auto og = iter.first; | |
| 1311 | - if (!isCached(og)) { | |
| 1312 | - m->obj_cache[og] = | |
| 1313 | - ObjCache(QPDF_Unresolved::create(this, og), -1, -1); | |
| 1314 | - if (this->m->reconstructed_xref) { | |
| 1315 | - break; | |
| 1316 | - } | |
| 1317 | - } | |
| 1318 | - } | |
| 1319 | - } | |
| 1320 | - // Second pass is skipped if the first pass did not trigger | |
| 1321 | - // reconstruction of the xref table. | |
| 1322 | - if (this->m->reconstructed_xref) { | |
| 1323 | - for (auto const& iter: this->m->xref_table) { | |
| 1324 | - auto og = iter.first; | |
| 1325 | - if (!isCached(og)) { | |
| 1326 | - m->obj_cache[og] = | |
| 1327 | - ObjCache(QPDF_Unresolved::create(this, og), -1, -1); | |
| 1328 | - } | |
| 1329 | - } | |
| 1304 | + // Make sure everything in the xref table appears in the object | |
| 1305 | + // cache. | |
| 1306 | + for (auto const& iter: this->m->xref_table) { | |
| 1307 | + auto og = iter.first; | |
| 1308 | + if (!isCached(og)) { | |
| 1309 | + m->obj_cache[og] = | |
| 1310 | + ObjCache(QPDF_Unresolved::create(this, og), -1, -1); | |
| 1330 | 1311 | } |
| 1331 | 1312 | } |
| 1332 | - // Final pass adds all indirect references to the object cache. | |
| 1313 | + | |
| 1314 | + // Resolve all known objects. The parser inserts any indirect | |
| 1315 | + // reference into the object cache, including dangling references. | |
| 1316 | + bool orig_reconstructed_xref = this->m->reconstructed_xref; | |
| 1317 | + bool triggered_xref_reconstruction = false; | |
| 1333 | 1318 | for (auto const& iter: this->m->obj_cache) { |
| 1334 | 1319 | resolve(iter.first); |
| 1320 | + if (!orig_reconstructed_xref && this->m->reconstructed_xref) { | |
| 1321 | + triggered_xref_reconstruction = true; | |
| 1322 | + // We triggered xref reconstruction. We'll have to start | |
| 1323 | + // over. | |
| 1324 | + break; | |
| 1325 | + } | |
| 1326 | + } | |
| 1327 | + if (triggered_xref_reconstruction) { | |
| 1328 | + // Resolving objects triggered xref reconstruction. This may | |
| 1329 | + // cause new objects to appear in the xref. Start over again. | |
| 1330 | + // This recursive call can never go more than two deep since | |
| 1331 | + // we never clear this->m->reconstructed_xref. | |
| 1332 | + QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction"); | |
| 1333 | + fixDanglingReferences(force); | |
| 1334 | + } else { | |
| 1335 | + this->m->fixed_dangling_refs = true; | |
| 1335 | 1336 | } |
| 1336 | - this->m->fixed_dangling_refs = true; | |
| 1337 | 1337 | } |
| 1338 | 1338 | |
| 1339 | 1339 | size_t | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -678,3 +678,4 @@ QPDF_json bad pushedinheritedpageresources 0 |
| 678 | 678 | QPDFPageObjectHelper copied fallback 0 |
| 679 | 679 | QPDFPageObjectHelper used fallback without copying 0 |
| 680 | 680 | QPDF skipping cache for known unchecked object 0 |
| 681 | +QPDF fix dangling triggered xref reconstruction 0 | ... | ... |
qpdf/qtest/dangling-refs.test
| ... | ... | @@ -19,21 +19,13 @@ my $n_tests = 2 * scalar(@dangling); |
| 19 | 19 | |
| 20 | 20 | foreach my $f (@dangling) |
| 21 | 21 | { |
| 22 | - # TEMPORARY | |
| 23 | - my $xflags = 0; | |
| 24 | - if ($f eq 'dangling-bad-xref') | |
| 25 | - { | |
| 26 | - $xflags = $td->EXPECT_FAILURE; | |
| 27 | - } | |
| 28 | - # END TEMPORARY | |
| 29 | 22 | $td->runtest("dangling refs: $f", |
| 30 | 23 | {$td->COMMAND => "test_driver 53 $f.pdf"}, |
| 31 | 24 | {$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0}, |
| 32 | - $td->NORMALIZE_NEWLINES | $xflags); | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 33 | 26 | $td->runtest("check output", |
| 34 | 27 | {$td->FILE => "a.pdf"}, |
| 35 | - {$td->FILE => "$f-dangling-out.pdf"}, | |
| 36 | - $xflags); | |
| 28 | + {$td->FILE => "$f-dangling-out.pdf"}); | |
| 37 | 29 | } |
| 38 | 30 | cleanup(); |
| 39 | 31 | $td->report($n_tests); | ... | ... |