Skip to content

Fix out-of-bounds write when a clip path lies outside the image - #591

Open
Graveflo wants to merge 1 commit into
treeform:masterfrom
Graveflo:clip_bounds
Open

Fix out-of-bounds write when a clip path lies outside the image#591
Graveflo wants to merge 1 commit into
treeform:masterfrom
Graveflo:clip_bounds

Conversation

@Graveflo

@GravefloGraveflo commented Jul 30, 2026

Copy link
Copy Markdown

FYI

  • discovered and implemented by AI (GPT-5.6-Sol & Opus 5)
  • test fails on master
  • performance assessment at the bottom

Summary

Context.clip with a clip region that lies fully outside the canvas writes
outside the image buffer. Depending on where the write lands it raises
IndexDefect or segfaults inside the SIMD fill.

A clip region outside the canvas is ordinary Canvas2D usage — it is what you get
when clipping to something that has scrolled off — so this is reachable from the
public API without doing anything unusual.

Reproduced against 6.1.0 and against current master.

Reproduction

import pixie
let
image =newImage(420, 460)
ctx = image.newContext()
let a =newPath()
a.rect(0, 0, 420, 460)
ctx.clip(a) # first clip: mask == nil -> OverwriteBlendlet b =newPath()
b.rect(0, 500, 200, 100) # entirely below the image
ctx.clip(b) # second clip: mask != nil -> MaskBlend

Performance

The patch changes behavior in three of the four off-canvas directions. Only one
of those three has a "before" time worth comparing, because the other two
crashed:

clip regionbeforeafter
below the canvasout-of-bounds writecorrect — no meaningful timing to compare
above the canvasout-of-bounds writecorrect — no meaningful timing to compare
right of the canvasreturned immediately, silently dropping the clipcorrect, and now costs one mask clear
left of the canvasalready correctunchanged

So the case that gets slower is the one that previously produced a wrong result
without faulting: a MaskBlend fill whose path lies entirely right of the
canvas, which is the pathWidth == 0 early return.

How much, per ctx.clip() call:

canvasoff-canvas clip, beforeoff-canvas clip, afteron-canvas clip, for scale
420×46097 µs102 µs104 µs
1000×1000498 µs528 µs531 µs
1920×10801,044 µs1,103 µs1,104 µs

+5 to +59 µs on a call that already costs 97 to 1,044 µs — about 5%, scaling
with canvas area as any mask operation does.

After the fix, clipping to an off-canvas region costs the same as clipping to an on-canvas one.

@Graveflo
Graveflo marked this pull request as draft July 30, 2026 17:19
@Graveflo
Graveflo marked this pull request as ready for review July 30, 2026 19:08
Sign up for freeto 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

@Graveflo