Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 9197450e126a7cb9906153e40ad0c97e731fec73
https://github.com/WebKit/WebKit/commit/9197450e126a7cb9906153e40ad0c97e731fec73
Author: Mike Wyrzykowski <[email protected]>
Date: 2026-10-13 (Tue, 13 Oct 2026)
Changed paths:
A
LayoutTests/fast/webgpu/copy-external-image-video-frame-odd-width-expected.txt
A LayoutTests/fast/webgpu/copy-external-image-video-frame-odd-width.html
A LayoutTests/fast/webgpu/copy-image-non-bitmap-source-expected.txt
A LayoutTests/fast/webgpu/copy-image-non-bitmap-source.html
M Source/WebCore/Modules/WebGPU/GPUQueue.cpp
Log Message:
-----------
MallocSpan crash in GPUQueue::copyExternalImageToTexture
https://bugs.webkit.org/show_bug.cgi?id=324153
rdar://187345349
Reviewed by Dan Glastonbury.
copyExternalImageToTexture()'s CPU readback path trusted what CGImage reported
about a decoded image, and trusted that an <img> holds either a BitmapImage or
an SVGImage. Neither holds, which left the path with an out of bounds read, a
null dereference, and a few smaller defects. Each is fixed here:
- clipTo8bitsPerChannel() left byteSpanBacking untouched for a bits per
component it did not know how to narrow, and the caller used it anyway.
The span was empty, so bytesPerPixel came out zero, maxChannelIndex
underflowed to SIZE_MAX, and the pixel loop read past the end of the
buffer. It returns false now, and the copy is rejected.
- An <img> can also hold a PDFDocumentImage, which is neither a BitmapImage
nor an SVGImage. dynamicDowncast<SVGImage>() returned null for one and the
result was dereferenced unconditionally. Only an SVGImage takes that branch
now; a PDFDocumentImage has no pixels of its own to copy, so the copy is
rejected.
- The pixel loop's reads are bounded against the length of the data the
provider actually returned, rather than against the CGImage metadata, which
is not guaranteed to agree with it. The sizes are computed with CheckedSize,
so an implausible width or height cannot wrap.
- bytesPerPixel is the channel count, from CGImageGetBitsPerPixel() over
CGImageGetBitsPerComponent(), rather than the decoded size divided by the
pixel count. The latter folded end of row padding into it, which both
overstated the pixel size and misplaced every channel read: an 8x8
grayscale image whose rows were padded to 32 bytes looked like it had 4
bytes per pixel. That image also satisfied the fast path, which handed the
gray bytes over as though they were RGBA, so the fast path now requires 4
bytes per pixel and rows without padding.
- CGImageGetAlphaInfo() is not guaranteed to return one of the enumerators
the channel mapping switches over, so the lambda could fall off the end.
It returns a default now.
- The orientation is read from the CachedImage already fetched above and
tolerates it having no image, rather than going back through the element.
- The video frame path gets the same length check. On top of that,
vImagePermuteChannels_ARGB8888() touches width * 4 bytes of every row, so
the image is required here to be 32 bits per pixel with a stride at least
that wide, instead of inheriting that from the conformer in the GPU process
several layers up; and the stride CoreGraphics reports is what rowBytes is
set to, rather than the data length divided by the height, so a frame whose
rows CoreVideo padded is walked correctly.
Tests: fast/webgpu/copy-external-image-video-frame-odd-width.html
fast/webgpu/copy-image-non-bitmap-source.html
*
LayoutTests/fast/webgpu/copy-external-image-video-frame-odd-width-expected.txt:
Added.
* LayoutTests/fast/webgpu/copy-external-image-video-frame-odd-width.html: Added.
* LayoutTests/fast/webgpu/copy-image-non-bitmap-source-expected.txt: Added.
* LayoutTests/fast/webgpu/copy-image-non-bitmap-source.html: Added.
* Source/WebCore/Modules/WebGPU/GPUQueue.cpp:
(WebCore::getImageBytesFromVideoFrame):
(WebCore::clipTo8bitsPerChannel):
(WebCore::imageBytesForSource):
Canonical link: https://commits.webkit.org/323636@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications