Skip to content

fix: don't crash rendering a clipped/masked group entirely outside the canvas - #419

Open
ptz0n wants to merge 1 commit into
thx:mainfrom
ptz0n:fix/wasm-off-canvas-panic-and-reset
Open

ptz0n wants to merge 1 commit into
thx:mainfrom
ptz0n:fix/wasm-off-canvas-panic-and-reset

Conversation

@ptz0n

@ptz0n ptz0n commented Sep 8, 2026

Copy link
Copy Markdown

The wasm build crashes hard on ordinary SVG content: any <g> with a clip-path/mask/filter/isolated opacity whose content extends off-canvas triggers a RuntimeError: unreachable. That's not a rare shape — a background layer bigger than its viewport, a virtualized list row placed off-screen, anything like that.

Root cause is in resvg, not here: fit_to_rect clamps each rect edge independently and only inward, so a rect entirely past one bound produces an inverted rect that panics on .unwrap() instead of returning None. RazrFalcon fixed this exact bug upstream in June 2023 (4a08e34, closes #638). The resvg fork this crate pins diverged before that fix landed and never picked it up — the fork's own current master has since picked it up too via a later, unrelated sync with upstream, but that's 3 major versions and ~40 commits ahead of the specific old commit this crate is actually pinned to, and not semver-compatible with it. So I reapplied the fix directly on top of that old pinned commit: ptz0n/resvg@1759f23. (I'd opened a PR for this against the fork too, but closed it — nothing for its master to merge, since master already has the fix.)

Tested against 660 real, structurally distinct production SVGs, rendered through this crate's own wasm build: 120 crashed before this fix, 0 after. Added a regression test for the minimal case.

Also in this PR:

  • console_error_panic_hook, wired into the Resvg constructor. Right now any wasm panic just says unreachable — no message, no location. This is how I actually found the bug above; without it this would've been a lot harder to track down.
  • resetWasm(). wasm32 linear memory only grows, never shrinks. A long-lived host that renders enough structurally varied SVGs can still accumulate memory over time even with correct .free() calls everywhere. This lets a caller discard the instance and start fresh without restarting the whole process.

Split into separate PRs if you'd rather review them independently — bundled here since I found and fixed all three while debugging one production issue.

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

@ptz0n is attempting to deploy a commit to the yisibl's projects Team on Vercel.

A member of the Team first needs to authorize it.

@ptz0n
ptz0n force-pushed the fix/wasm-off-canvas-panic-and-reset branch from 1479289 to 9cdf875 Compare September 8, 2026 18:06
…e canvas

Points the resvg patch at a fork carrying linebender/resvg@4a08e340
(closes #638), which this crate's pinned fork missed. Also adds
console_error_panic_hook and resetWasm().
@ptz0n
ptz0n force-pushed the fix/wasm-off-canvas-panic-and-reset branch from 9cdf875 to a139cd5 Compare September 8, 2026 18:16
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.

1 participant