pub struct Limits {Show 18 fields
pub max_object_nesting: u32,
pub max_array_len: usize,
pub max_xref_size: u32,
pub max_object_number: u32,
pub header_scan: u64,
pub startxref_scan: u64,
pub max_word_len: usize,
pub max_page_tree_depth: u32,
pub max_page_count: u32,
pub max_decoded_stream_len: usize,
pub max_cmap_ranges: usize,
pub max_name_tree_depth: u32,
pub max_script_loop_iterations: u64,
pub max_script_recursion: usize,
pub max_script_stack: usize,
pub max_calculate_depth: u32,
pub max_render_pixels: Option<u64>,
pub deadline: Option<Deadline>,
}Expand description
Caps applied while reading a document. Plain configuration data: pass it down, never store it in a parser struct that also owns state.
Which operations honour which cap: the parser’s caps (nesting, array
length, xref size, object numbers, the scans, word length, the page tree,
stream length) are read while opening and while fetching objects; the
CMap and name-tree caps while loading fonts and document-level trees; the
script budgets by the script engine alone. Limits::max_render_pixels
is read by the facade’s render entry points, before a target is allocated.
Limits::deadline is read at every boundary listed on that field.
use pdfrum_common::Limits;
// PDFium-equivalent defaults, with one cap tightened for a fuzz budget.
let limits = Limits { max_array_len: 1 << 20, ..Limits::default() };
assert_eq!(limits.max_object_nesting, 64);
assert_eq!(limits.max_object_number, 25_165_824);Fields§
§max_object_nesting: u32Maximum depth of nested arrays/dictionaries accepted while parsing an object body. Enforced at parse time so access code may recurse freely.
max_array_len: usizeMaximum number of elements in one array. PDFium has no such cap; ours
is consulted by the object parser (pdfrum_parser::syntax), the
ToUnicode CMap reader and the Type 1 charstring decoder.
max_xref_size: u32Maximum number of entries a cross-reference section may declare; one past the largest legal object number.
max_object_number: u32Largest legal object number. PDFium: kMaxObjectNumber (24·2²⁰).
header_scan: u64How far from the start of the file the %PDF- header is searched for.
startxref_scan: u64How far back from the end of the file startxref is searched for.
max_word_len: usizeMaximum number of bytes kept from one syntax token (names, keywords). Longer tokens are truncated, matching PDFium’s word buffer.
max_page_tree_depth: u32Maximum depth of the page tree walk before it gives up.
max_page_count: u32Maximum number of pages a document may report.
max_decoded_stream_len: usizeMaximum number of bytes any single stream filter may produce.
PDFium has no cap here: Flate and LZW decode until they stop, and
only the size it reports saturates, at kMaxTotalOutSize = 1 GiB
(flatemodule.cpp), silently truncating anything larger. We decline to
inherit that zip-bomb surface and turn the same ceiling into a hard
rejection instead; past 1 GiB the oracle’s reported size has already
stopped tracking its content, so no stream that decodes faithfully in
the C++ changes behavior. RunLengthDecode keeps its own, much
smaller and behaviorally load-bearing 20 MiB cap in pdfrum-filters.
max_cmap_ranges: usizeMaximum number of codespace ranges, and separately of wide-code CID ranges, one embedded CMap program may declare.
PDFium has no cap: both lists grow with the program. The default here
is one range per possible two-byte code, which no real CMap approaches
and which bounds a hostile program’s memory at a few megabytes; past it
further ranges are dropped with a diagnostic rather than erroring, in
the same spirit as max_decoded_stream_len.
max_name_tree_depth: u32Maximum depth of a name tree, number tree, structure tree, form-field
/Parent walk, field-name trie, or chained /Next action.
PDFium caps four of those six at 32 and leaves the number tree and the action chain uncapped — both of which are unbounded recursion on a cyclic file. One knob covers all six; no real document approaches it, and exceeding it answers “not found” with a diagnostic rather than erroring.
max_script_loop_iterations: u64How many loop iterations one script may run before it is stopped.
Roughly ten seconds of the tightest possible loop. No real form script
iterates a thousand times; the number is a ceiling on a hostile file,
not a budget a legitimate one has to fit inside. Exhausting it is a
Diagnostic and the refusing answer from the hook that was running
— never a hang, never a panic, and never a silent acceptance.
PDFium has no equivalent at all: while(true){} under V8 runs until
the process is killed from outside.
max_script_recursion: usizeHow deep one script may recurse. boa’s own default.
max_script_stack: usizeHow large one script’s value stack may grow. boa’s own default.
max_calculate_depth: u32How deep a calculation may trigger another calculation.
One, because a calculation that runs during another calculation is refused rather than counted down: the outer sweep is authoritative and every nested call returns immediately. The field makes that depth configurable rather than looser.
max_render_pixels: Option<u64>The most pixels one render may produce: width × height of the target
under the render transform. None — the default — is no cap.
PDFium has none: pdfium_test --scale sizes the bitmap and only
CFX_DIBitmap’s pitch overflow refuses it. Read by the facade before
the target is allocated, so a request above the cap costs nothing;
exceeding it is LimitExceeded::RenderPixels.
deadline: Option<Deadline>When every operation on the document must have stopped. None — the
default — is no limit.
A Deadline is a stop flag any thread raises
(Deadline::manual and Deadline::stop, the mechanism every
target has) and, on targets with a clock, a budget that raises it for
you (Deadline::after). A host on wasm32 has only the flag, and
its own timer.
Honoured cooperatively, at the boundaries the engine already has:
opening (once on entry, then every 4096 tokens of a cross-reference
rebuild scan), loading a page, interpreting a content stream (every
256 operators), rasterizing (every object), extracting a page’s text
(on entry), and running a script (on entry). The fallible entries —
open, page load, render — answer LimitExceeded::Time for a spent
budget and LimitExceeded::Stopped for a raised flag; the
infallible ones — the interpreter, the extractor — stop where they
are, record DiagKind::TimeLimitReached and return what they have;
a script refuses as an exhausted script budget does. PDFium has no
equivalent: a host wraps the process in a timer.
Implementations§
Source§impl Limits
impl Limits
Sourcepub fn check_deadline(&self, during: Operation) -> Result<(), LimitExceeded>
pub fn check_deadline(&self, during: Operation) -> Result<(), LimitExceeded>
Ok unless a deadline is set and has passed — the one call every
cooperative boundary makes. Costs one branch without a deadline.
§Errors
LimitExceeded::Time once the deadline has passed.