Skip to content

Fix out-of-bounds read in blendLineCoverageMaskAvx2 - #592

Open
Graveflo wants to merge 1 commit into
treeform:masterfrom
Graveflo:avx-bug
Open

Fix out-of-bounds read in blendLineCoverageMaskAvx2#592
Graveflo wants to merge 1 commit into
treeform:masterfrom
Graveflo:avx-bug

Conversation

@Graveflo

Copy link
Copy Markdown

FYI

  • discovered and implemented by AI (GPT-5.6-Sol & Opus 5)
  • test fails on master
  • does not seem to negatively affect performance

Summary

blendLineCoverageMaskAvx2 advances 32 pixels per iteration but guards the loop
with i < len - 16. An iteration can therefore start within 32 pixels of the
end and read 32 coverage bytes from a buffer holding only len, then blend and
store up to 16 pixels past the end of the coverage run.

Any MaskBlend fill whose path is wide enough to reach the vector loop can hit
it. Context.clip uses MaskBlend for every clip after the first, so this is
reachable from ordinary Canvas2D code.

Reproduction

import pixie

const w = 60
let
  image = newImage(w, w)
  paint = newPaint(SolidPaint)
  path = newPath()
paint.color = color(1, 0, 0, 1)
paint.blendMode = MaskBlend
path.circle(circle(vec2(w / 2, w / 2), w / 2))
image.fillPath(path, paint)
nim c -r --mm:arc -d:useMalloc -d:release --passC:-fsanitize=address --passL:-fsanitize=address repro.nim

Without a sanitizer the read lands on readable heap and the damage is visible
only as a few stray pixels past the right end of each scanline's coverage run —
which is why it has gone unnoticed.

The width that triggers it depends on where the 32-byte alignment prologue
leaves the index, so a single width is not a reliable reproduction.

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