Skip to content

Fix freeze and panic on size-less SVG with huge content bbox (#939)#1082

Open
StefanoD wants to merge 2 commits into
linebender:mainfrom
StefanoD:fix/939-huge-auto-canvas-freeze
Open

Fix freeze and panic on size-less SVG with huge content bbox (#939)#1082
StefanoD wants to merge 2 commits into
linebender:mainfrom
StefanoD:fix/939-huge-auto-canvas-freeze

Conversation

@StefanoD

Copy link
Copy Markdown

Fixes #939.

Two independent defects, both triggered by <svg ls="3.2"><path d="M-7-96 6 0 07 4E7"/></svg>:

  1. Freeze — without an explicit width/height/viewBox, the canvas is derived from the content's bounding box. The 4E7 (= 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, so resvg file.svg hung for tens of seconds (longer / OOM on the reporter's machine). The auto-derived size is now capped at i16::MAX. SVGs that declare an explicit size are unaffected.

  2. Panicresvg -w 100 file.svg panicked at crates/resvg/src/lib.rs:46 because the clip-region extent (width * 5) of the upscaled pixmap overflowed i32, which IntRect::from_xywh rejects, so the .unwrap() failed. The computation now runs in i64 and clamps to the valid i32 range.

Each fix has its own commit and a regression test. The panic test exercises the max_bbox helper directly with a large IntSize, 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.


Note: I accidentally closed the original PR (#1064) by deleting my fork, which auto-closed it. This reopens the same change — the branch and commits are unchanged.

StefanoD and others added 2 commits June 14, 2026 15:28
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Freeze when trying to render some svg

1 participant