Skip to content

Fix integer overflow in Vulkan/Metal buffer size and pitch calculations#106

Open
mohammadmseet-hue wants to merge 1 commit intogoogle:mainfrom
mohammadmseet-hue:fix-vulkan-metal-integer-overflow-pitch-alloc
Open

Fix integer overflow in Vulkan/Metal buffer size and pitch calculations#106
mohammadmseet-hue wants to merge 1 commit intogoogle:mainfrom
mohammadmseet-hue:fix-vulkan-metal-integer-overflow-pitch-alloc

Conversation

@mohammadmseet-hue
Copy link
Copy Markdown

Summary

The Terracotta initiative (commits 88ff9f4, a7d24e6) fixed integer overflow in D3D11 backend buffer allocation and Metal sizeInBytes calculation. However, several equivalent overflow patterns in the Vulkan and Metal backends were missed.

When processing large textures (e.g. RGBA32F at GL_MAX_TEXTURE_SIZE=16384), multiplication of pixelBytes * width * height exceeds UINT32_MAX, wrapping to a small value. This causes undersized buffer allocation followed by writes of the full image data.

Affected Code

File Variable Issue
vk_helpers.cpp:11538 allocationSize readFormat->pixelBytes * area.width * area.height in 32-bit
TextureVk.cpp:3176-3183 srcDataRowPitch, dstDataRowPitch etc. GLuint pitch calculations overflow
SurfaceVk.cpp:286 rowStride GLuint overflow before VkDeviceSize widening
UtilsVk.cpp:4287-4290 sliceTexels, sliceSize, texBufferSize Chained GLuint overflows
FrameBufferMtl.mm:95 bytesPerRow uint32_t not fixed by Terracotta (only sizeInBytes was fixed)

Fix

Widen all affected variables to size_t or VkDeviceSize with explicit static_cast<size_t>() before multiplication, matching the approach used in the Terracotta D3D11 fix.

Testing

Existing tests continue to pass. The overflow is triggered by large textures (e.g. RGBA32F 16384x16384) which are within GL_MAX_TEXTURE_SIZE on most desktop and mobile Vulkan GPUs.

The Terracotta initiative (commits 88ff9f4, a7d24e6) fixed integer overflow
in D3D11 backend buffer allocation and Metal sizeInBytes calculation, but
several equivalent overflow patterns in the Vulkan and Metal backends were
missed.

When processing large textures (e.g. RGBA32F at GL_MAX_TEXTURE_SIZE=16384),
multiplication of pixelBytes * width * height exceeds UINT32_MAX, wrapping
to a small value. This causes undersized buffer allocation followed by
writes of the full image data, resulting in heap buffer overflow.

Fixed locations:
- vk_helpers.cpp readPixelsImpl: allocationSize computed in 32-bit
- TextureVk.cpp reformatStagedUpdate: GLuint pitch variables overflow
- SurfaceVk.cpp: GLuint rowStride overflow before VkDeviceSize widening
- UtilsVk.cpp: GLuint sliceTexels/sliceSize/texBufferSize chain overflow
- FrameBufferMtl.mm: uint32_t bytesPerRow not fixed by Terracotta

All fixed by widening to size_t/VkDeviceSize before multiplication.
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