Skip to content

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

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)#1064
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.

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>
@StefanoD StefanoD force-pushed the fix/939-huge-auto-canvas-freeze branch from 8b872c8 to 6089918 Compare June 14, 2026 13:33
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>
@StefanoD StefanoD force-pushed the fix/939-huge-auto-canvas-freeze branch from 6089918 to 1803885 Compare June 14, 2026 13:41
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