From 635035efd133177e6d8c52372de7ca84c9e6ed3a Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Tue, 13 Jan 2026 18:40:55 -0500 Subject: [PATCH] Add an xref table offset array to better detect xref table loops (Issue #148) --- CHANGES.md | 1 + pdfio-file.c | 33 +++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 10d2f1e..f54ff70 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ v1.6.2 - YYYY-MM-DD - Increased the maximum length of a single string to 128k (Issue #146) - Added missing range checks to `pdfioArrayCopy` and `pdfioDictCopy`. - Refactored PDF encryption code to fix unlocking with certain files. +- Improved xref table loop detection (Issue #148) - Fixed an error propagation bug when reading too-long values (Issue #146) - Fixed a Clang warning. diff --git a/pdfio-file.c b/pdfio-file.c index e30c63d..5bcc4d7 100644 --- a/pdfio-file.c +++ b/pdfio-file.c @@ -1,7 +1,7 @@ // // PDF file functions for PDFio. // -// Copyright © 2021-2025 by Michael R Sweet. +// Copyright © 2021-2026 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -2006,6 +2006,9 @@ load_xref( _pdfio_token_t tb; // Token buffer/stack off_t line_offset; // Offset to start of line pdfio_obj_t *pages_obj; // Pages object + size_t num_xrefs = 1; // Number of xref offsets + off_t xrefs[100] = { xref_offset }; + // xref offsets while (!done) @@ -2471,13 +2474,31 @@ load_xref( { done = true; } - else if (new_offset == xref_offset) + else { - _pdfioFileError(pdf, "Recursive xref table."); - return (false); - } + // See if we've seen this xref table before... + size_t i; // Looping var - xref_offset = new_offset; + for (i = 0; i < num_xrefs; i ++) + { + if (new_offset == xrefs[i]) + { + // Yes, error out... + _pdfioFileError(pdf, "Recursive xref table."); + return (false); + } + } + + // No, save it... + if (i >= (sizeof(xrefs) / sizeof(xrefs[0]))) + { + // Too many xref tables... + _pdfioFileError(pdf, "Too many xref tables."); + return (false); + } + + xrefs[num_xrefs ++] = xref_offset = new_offset; + } } // Once we have all of the xref tables loaded, get the important objects and