aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-11-26 22:43:41 +0100
committerJay Berkenbilt <jberkenbilt@users.noreply.github.com>2022-11-27 00:13:46 +0100
commitff42ea4e6cb8b03badf31993fcb4d9f57bb2ad1e (patch)
treee975aad05cbc029419ab75a090821e6a1a1d045d
parent1d9209ee743a34597de6965edf40333a3eca47b8 (diff)
downloadqpdf-ff42ea4e6cb8b03badf31993fcb4d9f57bb2ad1e.tar.zst
Fix logic for fixDanglingReferences
-rw-r--r--libqpdf/QPDF.cc60
-rw-r--r--qpdf/qpdf.testcov1
-rw-r--r--qpdf/qtest/dangling-refs.test12
3 files changed, 33 insertions, 40 deletions
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 7e3326e8..89487ee1 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -1292,48 +1292,48 @@ QPDF::showXRefTable()
}
}
-// Ensure all objects in the pdf file, including those in indirect references,
-// appear in the object cache.
void
QPDF::fixDanglingReferences(bool force)
{
+ // Ensure all objects in the pdf file, including those in indirect
+ // references, appear in the object cache.
if (this->m->fixed_dangling_refs && !force) {
return;
}
- if (!this->m->fixed_dangling_refs) {
- // First pass is only run if the the xref table has not been
- // reconstructed. It will be terminated as soon as reconstruction is
- // triggered.
- if (!this->m->reconstructed_xref) {
- for (auto const& iter: this->m->xref_table) {
- auto og = iter.first;
- if (!isCached(og)) {
- m->obj_cache[og] =
- ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
- if (this->m->reconstructed_xref) {
- break;
- }
- }
- }
- }
- // Second pass is skipped if the first pass did not trigger
- // reconstruction of the xref table.
- if (this->m->reconstructed_xref) {
- for (auto const& iter: this->m->xref_table) {
- auto og = iter.first;
- if (!isCached(og)) {
- m->obj_cache[og] =
- ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
- }
- }
+ // Make sure everything in the xref table appears in the object
+ // cache.
+ for (auto const& iter: this->m->xref_table) {
+ auto og = iter.first;
+ if (!isCached(og)) {
+ m->obj_cache[og] =
+ ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
}
}
- // Final pass adds all indirect references to the object cache.
+
+ // Resolve all known objects. The parser inserts any indirect
+ // reference into the object cache, including dangling references.
+ bool orig_reconstructed_xref = this->m->reconstructed_xref;
+ bool triggered_xref_reconstruction = false;
for (auto const& iter: this->m->obj_cache) {
resolve(iter.first);
+ if (!orig_reconstructed_xref && this->m->reconstructed_xref) {
+ triggered_xref_reconstruction = true;
+ // We triggered xref reconstruction. We'll have to start
+ // over.
+ break;
+ }
+ }
+ if (triggered_xref_reconstruction) {
+ // Resolving objects triggered xref reconstruction. This may
+ // cause new objects to appear in the xref. Start over again.
+ // This recursive call can never go more than two deep since
+ // we never clear this->m->reconstructed_xref.
+ QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction");
+ fixDanglingReferences(force);
+ } else {
+ this->m->fixed_dangling_refs = true;
}
- this->m->fixed_dangling_refs = true;
}
size_t
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index b1c9e697..3cef71d2 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -678,3 +678,4 @@ QPDF_json bad pushedinheritedpageresources 0
QPDFPageObjectHelper copied fallback 0
QPDFPageObjectHelper used fallback without copying 0
QPDF skipping cache for known unchecked object 0
+QPDF fix dangling triggered xref reconstruction 0
diff --git a/qpdf/qtest/dangling-refs.test b/qpdf/qtest/dangling-refs.test
index c63d5acd..18c2cf6b 100644
--- a/qpdf/qtest/dangling-refs.test
+++ b/qpdf/qtest/dangling-refs.test
@@ -19,21 +19,13 @@ my $n_tests = 2 * scalar(@dangling);
foreach my $f (@dangling)
{
- # TEMPORARY
- my $xflags = 0;
- if ($f eq 'dangling-bad-xref')
- {
- $xflags = $td->EXPECT_FAILURE;
- }
- # END TEMPORARY
$td->runtest("dangling refs: $f",
{$td->COMMAND => "test_driver 53 $f.pdf"},
{$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0},
- $td->NORMALIZE_NEWLINES | $xflags);
+ $td->NORMALIZE_NEWLINES);
$td->runtest("check output",
{$td->FILE => "a.pdf"},
- {$td->FILE => "$f-dangling-out.pdf"},
- $xflags);
+ {$td->FILE => "$f-dangling-out.pdf"});
}
cleanup();
$td->report($n_tests);