latex-rust 1.0.5
Upgrade notice. Versions 1.0.0 through 1.0.4 abort the whole process with a stack overflow when given deeply nested input. If your program renders LaTeX from any untrusted source, upgrade to 1.0.5:
cargo update -p latex-rust1.0.5 has no API changes. It also includes the 2.0.0 rendering fixes that fit the 1.x API and the 2.0.1 egui fix, so most formulas now draw differently from 1.0.4 (see below).
Security
- Deeply nested input now returns an error instead of aborting the process (#6). The parser and the layout engine recursed once per nesting level with no limit. For example, 700 nested
\frac{1}{…}(about 7 KB of input) overflowed an 8 MiB stack in an optimised build, and far fewer levels were enough on smaller thread stacks. A stack overflow cannot be caught withcatch_unwind, so any program rendering untrusted LaTeX could be terminated.
Fixed
These fixes are backported from 2.0.0 and draw the same output as 2.0.0.
- Superscripts, subscripts, limits, and fraction parts in text style are drawn at script size in the SVG, PNG, and egui renderers. Before, they were positioned at script size but drawn at full size. 2.0.0 added a
scalefield toBoxContent::Glyphfor this; 1.0.5 leaves that type unchanged and works out the scale from the glyph box's size instead. (#1) - Unstyled Latin letters and lowercase Greek letters are set in math italic (for example
xis drawn as U+1D465), as TeX does. Digits, uppercase Greek,\mathrm,\text, and operator names stay upright. (#2) - A math-mode
-is drawn as U+2212 MINUS SIGN instead of the hyphen. (#3) - Font switches such as
\mathbfand\mathrmreach nested subformulae (fractions, script bases, radicals), so\mathbf{\frac{a}{b}}is bold. (#4) - Diacritic accents (
\hat,\dot,\bar, and the rest) are placed by the TeX rule. Before, they sat one accent base height too high. (#5) - The egui backend renders every glyph. Before, formulas using
H,π,σ, math italict(so\partial_t u),#,$,€, and a few hundred other glyphs failed withError::Unsupported { what: "glyph tessellation" }, andB,k,τ,↦, and about 140 others were drawn with a stray triangle outside the glyph. This is the same fix as in 2.0.1.
Changed behaviour
- Input that nests more than 32 levels is refused.
parse,parse_with_colors, and thelatex_to_*functions returnParseError::Malformed("input nests deeper than 32 levels").layoutreturnsError::Unsupported { what: "tree nests deeper than 32 levels" }for a tree built by hand that nests that deeply. Both are existing error variants. - The count is of parser recursion levels, and a braced argument costs two, so the limit admits 15 nested
\frac,\sqrt, orx^{…}, and 31 nested groups,\left…\rightpairs, or environments. Deeper input that 1.0.4 rendered (for example 16 to about 650 nested fractions in an optimised build) is now refused. The limit and the messages are the same as in 2.0.0. - Rendered output changes because of the fixes above. On our 87-input test corpus, 82 inputs draw differently from 1.0.4, and all 87 draw exactly as in 2.0.1 (SVG, PNG, egui, and box dimensions). Code that pinned 1.0.4 images, dimensions, or glyph characters will see new values.
Not in 1.0.5
These 2.0.0 changes add or change public API, so they are only in 2.0.0: Dim::as_ratio(), MathFont::face() and the ttf_parser re-export (#7), STIX_TWO_MATH_OTF as a static (#11), and ParseOptions, parse_with_options, and layout_with_max_depth for changing the depth limit.
Stack use
With the deepest input the limit admits, an optimised build needs at most about 512 KiB of stack, and an unoptimised build up to about 4 MiB (nested matrix environments). If you render on a thread with less stack than that, give the rendering thread more.
Advisory
A RustSec advisory for the crash is being requested. Its identifier will be added here once it is assigned.
Thanks
Tom Clark (IronLAB) reported all of these issues with reproductions and proposed fixes, and wrote the fix for #4 and the depth limit (#6, #10). Both are backported here under his name.