Fix freeze and panic on size-less SVG with huge content bbox (#939)#1064
Open
StefanoD wants to merge 2 commits into
Open
Fix freeze and panic on size-less SVG with huge content bbox (#939)#1064StefanoD wants to merge 2 commits into
StefanoD wants to merge 2 commits into
Conversation
When an SVG declares no width/height/viewBox, the canvas size is derived from the content's bounding box. A single far-away coordinate (e.g. the malformed path `M-7-96 6 0 07 4E7`, where `4E7` is 40,000,000) blew this up to a 7 x 40,000,000 pixel (~1.1 GB) canvas, freezing rendering and PNG encoding for tens of seconds. Cap each auto-derived dimension at i16::MAX so such inputs render quickly (or fail fast at pixmap creation) instead of hanging. SVGs that declare an explicit size are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8b872c8 to
6089918
Compare
render() and render_node() build a clip region as 2x-negative / 5x-extent
around the target pixmap. For very large (e.g. heavily upscaled) pixmaps,
`width * 5` exceeds i32::MAX, which IntRect::from_xywh rejects, so the
following .unwrap() panicked.
Extract the computation into a max_bbox() helper that works in i64 and
clamps to the valid i32 range, degrading an over-large target into a
still-generous clip region instead of crashing.
Reproduction:
printf '%s' '<svg ls="3.2"><path d="M-7-96 6 0 07 4E7"/></svg>' > t.svg
resvg -w 100 t.svg out.png
Crash dump (debug build, RUST_BACKTRACE=full, std frames trimmed):
thread 'main' panicked at crates/resvg/src/lib.rs:46:6:
called `Option::unwrap()` on a `None` value
stack backtrace:
17: core::option::unwrap_failed
at library/core/src/option.rs:2251:5
18: core::option::Option<T>::unwrap
at library/core/src/option.rs:1016:21
19: resvg::render
at crates/resvg/src/lib.rs:46:6
20: resvg::render_svg
at crates/resvg/src/main.rs:743:9
21: resvg::process
at crates/resvg/src/main.rs:103:15
22: resvg::main
at crates/resvg/src/main.rs:12:21
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6089918 to
1803885
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #939.
Two independent defects, both triggered by
<svg ls="3.2"><path d="M-7-96 6 0 07 4E7"/></svg>:Freeze — without an explicit
width/height/viewBox, the canvas is derived from the content's bounding box. The4E7(= 40,000,000) coordinate produced a 7 x 40,000,000 px (~1.1 GB) canvas: rendering took 5.4 s and PNG encoding 22.3 s, soresvg file.svghung for tens of seconds (longer / OOM on the reporter's machine). The auto-derived size is now capped ati16::MAX. SVGs that declare an explicit size are unaffected.Panic —
resvg -w 100 file.svgpanicked atcrates/resvg/src/lib.rs:46because the clip-region extent (width * 5) of the upscaled pixmap overflowedi32, whichIntRect::from_xywhrejects, so the.unwrap()failed. The computation now runs ini64and clamps to the validi32range.Each fix has its own commit and a regression test. The panic test exercises the
max_bboxhelper directly with a largeIntSize, so it stands independent of the SVG (the panic is reachable via any heavily upscaled pixmap, e.g.-z).Note: the two commits are independently bisectable; please use "Rebase and merge" if you want to keep them separate.
Generated by Claude.