Skip to main content

Module limits

Module limits 

Source
Expand description

Runtime-configurable safety limits (omnist-spec section 2.4, D-9 to D-13).

The spec requires every implementation to enforce a finite limit on nesting depth, node count and integer digits, lets it pick the numbers (D-10), and requires it to document them (D-11). It also says an implementation SHOULD enforce a finite maximum input size in bytes (D-23), which this port does. This module is where this port documents them and where a caller changes them.

LimitDefaultCeilingField
Nesting depthDEFAULT_MAX_DEPTH (200)MAX_DEPTH_CEILING (250)Limits::max_depth
Node count (containers)DEFAULT_MAX_NODES (1 000 000)MAX_NODES_CEILING (10 000 000)Limits::max_nodes
Integer digitsDEFAULT_MAX_INT_DIGITS (4 300)MAX_INT_DIGITS_CEILING (43 000)Limits::max_int_digits
Input size, bytesDEFAULT_MAX_INPUT_BYTES (64 MiB)MAX_INPUT_BYTES_CEILING (1 GiB)Limits::max_input_bytes

The default of each of the first three is the spec’s reference default; the spec names no default for the input size (D-24), so 64 MiB is this port’s own choice: it is the cap that bounds parse cost, and the section on the input size below says how it was chosen. The ceilings are this port’s own (the spec recommends none for these three): a limit is a denial-of-service bound, not a tuning knob without an upper end, and the depth ceiling in particular keeps the recursive readers inside a thread’s stack: measured with a 2 MB thread stack, the JSON, OML, YAML and XML readers and Doc handle 300 levels in a debug build and 1 000 in a release build, but overflow at 400 in debug, so 250 is safe in both profiles. A caller on a smaller stack than 2 MB must lower the depth.

As for crate::formats::yaml::YamlReadOptions, 0 selects the default (a zero or unset value never widens a limit) and a value above its ceiling is refused by Limits::validate, never clamped.

A node is a container (an edge list), as D-9 counts them: keys and scalar values are not nodes, so a flat mapping of any number of scalar entries is one node. A document whose deepest leaf sits at depth max_depth is accepted and one level deeper is refused; likewise for the other two (a count or digit length equal to the limit is accepted).

Exceeding a limit raises document.limit.depth, document.limit.nodes, document.limit.int-digits or document.limit.input-size as a crate::error::DocumentError (E-11): depth and node count are properties of the document as a whole and carry path $, an over-long integer carries the Document path of that integer, and an input over the size limit carries $ too (it is a property of the input as a whole).

§The input size (D-23, D-24)

The size is bytes of the input as received, not characters: \u{e9} counts as two, and a leading byte-order mark counts as three, because the length is taken before the mark is stripped (D-15) and before any decoding or parsing. The check is the first thing every reader does, so document.limit.input-size is reported ahead of parse.invalid-encoding, of a doubled-BOM error and of every other diagnostic. An input of exactly the maximum is accepted. It applies to all five formats, to a YAML input with no alias included, and to crate::document::Doc::from_format for any registered format; the CLI also stops reading a file or stdin at the maximum plus one byte instead of buffering the rest (--max-input-bytes).

The default, 64 MiB, is chosen to bound the cost of the slowest codec library, not to promise that an input that large parses quickly: the spec says a cap bounds parse cost without making any parse fast, and asks an implementation to measure its slowest codec at the size it chooses (D-24). docs/limitations.md records the measurement and the behaviour change: before 0.9.0-alpha a reader took any size. Only Documents read from text or bytes are bounded: an OSD schema text is not (D-25 asks for a schema-size bound but gives it no code), and a Document built from native values has no input bytes.

The limits apply to every route into the model: the *_with readers of each format (crate::oml::read_oml_with, crate::formats::json::read_json_with, crate::formats::yaml::YamlReadOptions::with_limits, crate::formats::toml::read_toml_with, crate::formats::xml::read_xml_with) and the Document constructors crate::document::Doc::of_with and crate::document::Doc::from_raw_with. A crate::document::Doc remembers the limits it was built under, so a later add/set on it enforces the same ones.

Structs§

Limits
The safety limits of spec section 2.4 (nesting depth, node count, integer digits) and the maximum input size of D-23, taken by the *_with readers and, for the first three, by crate::document::Doc::from_raw_with.

Constants§

DEFAULT_MAX_DEPTH
The reference default for the maximum nesting depth (spec section 2.4).
DEFAULT_MAX_INPUT_BYTES
The default maximum input size in bytes (spec D-23, D-24): 64 MiB. The spec names no default; this port’s is chosen in the module documentation.
DEFAULT_MAX_INT_DIGITS
The reference default for the maximum integer digits (spec section 2.4).
DEFAULT_MAX_NODES
The reference default for the maximum node count (spec section 2.4).
MAX_DEPTH_CEILING
The largest maximum nesting depth Limits::validate accepts.
MAX_INPUT_BYTES_CEILING
The largest maximum input size Limits::validate accepts: 1 GiB.
MAX_INT_DIGITS_CEILING
The largest maximum integer digit count Limits::validate accepts.
MAX_NODES_CEILING
The largest maximum node count Limits::validate accepts.

Functions§

input_size_error
The D-23 refusal: document.limit.input-size at $ (the size is a property of the input as a whole, E-4a). hint says how to raise the maximum, in the caller’s own terms (a library option, a CLI flag).