From 9f1e4483c7349eb71892dbaf43718845f1b2822a Mon Sep 17 00:00:00 2001 From: Roland Shum Date: Wed, 23 Sep 2026 13:48:24 -0700 Subject: [PATCH 1/4] Harden integer ranges in parallel BC compression --- DirectXTex/DirectXTexCompress.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index b8d4557a..fdc7efe3 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -297,7 +297,18 @@ namespace return HRESULT_E_NOT_SUPPORTED; // Refactored version of loop to support parallel independance - const size_t nBlocks = std::max(1, (image.width + 3) / 4) * std::max(1, (image.height + 3) / 4); + const size_t nbWidthBlocks = std::max(1, (image.width >> 2) + ((image.width & 3) ? 1 : 0)); + const size_t nbHeightBlocks = std::max(1, (image.height >> 2) + ((image.height & 3) ? 1 : 0)); + + // The existing loop iterator and coordinate calculations use int. Limit + // the block count before narrowing and preserve their representable range. + if (image.width > static_cast(INT32_MAX) || image.height > static_cast(INT32_MAX) + || nbWidthBlocks > static_cast(INT32_MAX) / nbHeightBlocks) + { + return HRESULT_E_ARITHMETIC_OVERFLOW; + } + + const size_t nBlocks = nbWidthBlocks * nbHeightBlocks; bool fail = false; @@ -317,7 +328,7 @@ namespace continue; } - const int nbWidth = std::max(1, int((image.width + 3) / 4)); + const int nbWidth = static_cast(nbWidthBlocks); int y = nb / nbWidth; const int x = (nb - (y * nbWidth)) * 4; From a497ca68857d257fadc95c9124ccfa234f0caf99 Mon Sep 17 00:00:00 2001 From: Roland Shum Date: Wed, 23 Sep 2026 14:02:58 -0700 Subject: [PATCH 2/4] Apply repository formatting to block extent declarations --- DirectXTex/DirectXTexCompress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index fdc7efe3..ca78c9cc 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -297,7 +297,7 @@ namespace return HRESULT_E_NOT_SUPPORTED; // Refactored version of loop to support parallel independance - const size_t nbWidthBlocks = std::max(1, (image.width >> 2) + ((image.width & 3) ? 1 : 0)); + const size_t nbWidthBlocks = std::max(1, (image.width >> 2) + ((image.width & 3) ? 1 : 0)); const size_t nbHeightBlocks = std::max(1, (image.height >> 2) + ((image.height & 3) ? 1 : 0)); // The existing loop iterator and coordinate calculations use int. Limit From a04f4e5fe087379b62a14212499eec5b68e7bf5b Mon Sep 17 00:00:00 2001 From: Roland Shum Date: Thu, 24 Sep 2026 14:15:35 -0700 Subject: [PATCH 3/4] Use uint64_t intermediates for checked parallel block counts --- DirectXTex/DirectXTexCompress.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index ca78c9cc..63bdba25 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -297,18 +297,21 @@ namespace return HRESULT_E_NOT_SUPPORTED; // Refactored version of loop to support parallel independance - const size_t nbWidthBlocks = std::max(1, (image.width >> 2) + ((image.width & 3) ? 1 : 0)); - const size_t nbHeightBlocks = std::max(1, (image.height >> 2) + ((image.height & 3) ? 1 : 0)); - // The existing loop iterator and coordinate calculations use int. Limit - // the block count before narrowing and preserve their representable range. - if (image.width > static_cast(INT32_MAX) || image.height > static_cast(INT32_MAX) - || nbWidthBlocks > static_cast(INT32_MAX) / nbHeightBlocks) + // their input dimensions before calculating the block count. + if (image.width > static_cast(INT32_MAX) || image.height > static_cast(INT32_MAX)) { return HRESULT_E_ARITHMETIC_OVERFLOW; } - const size_t nBlocks = nbWidthBlocks * nbHeightBlocks; + // The dimension check keeps the rounded counts and their product within uint64_t. + const uint64_t nbWidthBlocks = std::max(1, (uint64_t(image.width) + 3) / 4); + const uint64_t nbHeightBlocks = std::max(1, (uint64_t(image.height) + 3) / 4); + const uint64_t nBlocks = nbWidthBlocks * nbHeightBlocks; + if (nBlocks > INT32_MAX) + { + return HRESULT_E_ARITHMETIC_OVERFLOW; + } bool fail = false; From 386480de9251fad6f8736543e22cd734d8acfbd7 Mon Sep 17 00:00:00 2001 From: Roland Shum Date: Thu, 24 Sep 2026 18:23:30 -0700 Subject: [PATCH 4/4] Narrow checked parallel block count to size_t --- DirectXTex/DirectXTexCompress.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index 63bdba25..ea49e53b 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -299,6 +299,7 @@ namespace // Refactored version of loop to support parallel independance // The existing loop iterator and coordinate calculations use int. Limit // their input dimensions before calculating the block count. + // Direct3D texture size limits are below INT32_MAX, so this should not pose a problem in practice. if (image.width > static_cast(INT32_MAX) || image.height > static_cast(INT32_MAX)) { return HRESULT_E_ARITHMETIC_OVERFLOW; @@ -307,12 +308,14 @@ namespace // The dimension check keeps the rounded counts and their product within uint64_t. const uint64_t nbWidthBlocks = std::max(1, (uint64_t(image.width) + 3) / 4); const uint64_t nbHeightBlocks = std::max(1, (uint64_t(image.height) + 3) / 4); - const uint64_t nBlocks = nbWidthBlocks * nbHeightBlocks; - if (nBlocks > INT32_MAX) + const uint64_t blockCount = nbWidthBlocks * nbHeightBlocks; + if (blockCount > INT32_MAX) { return HRESULT_E_ARITHMETIC_OVERFLOW; } + const auto nBlocks = static_cast(blockCount); + bool fail = false; size_t progress = 0;