Skip to content

Harden integer ranges in parallel BC compression - #744

Draft
Roland Shum (ShumWengSang) wants to merge 3 commits into
microsoft:mainfrom
ShumWengSang:fix/parallel-bc-integer-ranges
Draft

Roland Shum (ShumWengSang) wants to merge 3 commits into
microsoft:mainfrom
ShumWengSang:fix/parallel-bc-integer-ranges

Conversation

@ShumWengSang

@ShumWengSang Roland Shum (ShumWengSang) commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Add integer-range validation to the existing parallel BC compression iterator:

  • Reject dimensions outside the existing signed coordinate range before rounding.
  • Promote the dimensions to uint64_t, calculate the rounded block extents and their product, then check the signed loop-count limit before narrowing.
  • Reuse the checked width-block count inside the loop.

This follows the review suggestion to use wider intermediate arithmetic and cast back after checking the result. The dimension guard bounds the additions and product, as well as the later signed pixel-coordinate calculations.

This is a source-only, post-allocation arithmetic-hardening change. It does not move validation ahead of destination allocation, change the serial compression path, or change progress-callback behavior. Parallel inputs outside the helper's existing signed dimension/block-count range return an arithmetic-overflow error.

Validation

  • MSVC x64 and native x86 Release builds with OpenMP enabled: passed.
  • The revised candidate passed six bounded valid-image cases covering BC1/BC3/BC5 on both architectures, comparing serial/parallel output byte-for-byte; largest source was 4 MiB. Earlier x64 baseline runs passed the same ordinary-image cases.
  • A separate arithmetic predicate model passed 16 checks per executable, covering 32-bit and 64-bit dimension types, zero extents, signed-dimension limits, and block-product boundaries.
  • All executed tests had enforced 256 MiB process-tree and 90-second limits.
  • The repository's explicit CI clang-format configuration and git diff --check pass.

Limits

The arithmetic model is not an end-to-end large-image reproduction. No valid file-input reachability or large-allocation mitigation is claimed. No new maintained test-suite regression is included; the local ordinary-image and arithmetic harnesses are validation evidence only.

Comment thread DirectXTex/DirectXTexCompress.cpp Outdated

// Refactored version of loop to support parallel independance
const size_t nBlocks = std::max<size_t>(1, (image.width + 3) / 4) * std::max<size_t>(1, (image.height + 3) / 4);
const size_t nbWidthBlocks = std::max<size_t>(1, (image.width >> 2) + ((image.width & 3) ? 1 : 0));

@walbourn Chuck Walbourn (walbourn) Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a simpler solution would be to promote to uint64_t here and then cast it back after the check.

// The dimension check keeps the rounded counts and their product within uint64_t.
const uint64_t nbWidthBlocks = std::max<uint64_t>(1, (uint64_t(image.width) + 3) / 4);
const uint64_t nbHeightBlocks = std::max<uint64_t>(1, (uint64_t(image.height) + 3) / 4);
const uint64_t nBlocks = nbWidthBlocks * nbHeightBlocks;

@walbourn Chuck Walbourn (walbourn) Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this is great. end it with:

const uint64_t blockCount = nbWidthBlocks * nbHeightBlocks;

if (blockCount > INT32_MAX)
{
    return HRESULT_E_ARITHMETIC_OVERFLOW;
}

auto nBlocks = static_cast<size_t>(nBlocks);

That way for 32-bit builds, the loop stick with 32-bit loop values.

|| nbWidthBlocks > static_cast<size_t>(INT32_MAX) / nbHeightBlocks)
// their input dimensions before calculating the block count.
if (image.width > static_cast<size_t>(INT32_MAX) || image.height > static_cast<size_t>(INT32_MAX))
{

@walbourn Chuck Walbourn (walbourn) Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to add a comment here:

// Direct3D texture size limits are below INT32_MAX, so this should not pose a problem in practice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants