From 809c6e46cc5ec83a18ea42b4973bf06e36e4124e Mon Sep 17 00:00:00 2001
From: Cary Phillips <cary@ilm.com>
Date: Sat, 28 Mar 2026 14:52:02 -0700
Subject: [PATCH] Fix signed integer overflow in `LossyDctDecoder_execute()`
 pointer arithmetic

`numBlocksX` and `numBlocksY` are declared as `int`. Two pointer-offset
expressions in `LossyDctDecoder_execute()` multiplied them as signed
32-bit integers before using the result as a pointer offset:

    rowBlock[comp]   = rowBlock[comp - 1]   + numBlocksX * 64;
    currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY;

`dataWindow.max.x` is a signed 32-bit value in the EXR file format, so
`numBlocksX` can reach `(INT32_MAX + 7) / 8 = 268,435,456`. At that
point `numBlocksX * 64 = 17,179,869,184` overflows `int32`, and
`numBlocksX * numBlocksY` overflows even sooner. The wraparound
produces a small or negative pointer offset, causing `rowBlock[comp]`
and `currDcComp[comp]` to point into already-used or pre-buffer memory
rather than the intended component stride.

Fix: cast `numBlocksX` to `size_t` before multiplying so the
arithmetic is performed in pointer-sized unsigned arithmetic:

    rowBlock[comp]   = rowBlock[comp - 1]   + (size_t) numBlocksX * 64;
    currDcComp[comp] = currDcComp[comp - 1] + (size_t) numBlocksX * numBlocksY;

This is consistent with the allocation on the line above, which already
uses `(size_t) numComp * (size_t) numBlocksX * 64 * sizeof(uint16_t)`,
and with the packed-DC count check, which uses explicit `uint64_t` casts.

Made-with: Cursor
Signed-off-by: Cary Phillips <cary@ilm.com>
---
 src/lib/OpenEXRCore/internal_dwa_decoder.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: openexr-3.2.2/src/lib/OpenEXRCore/internal_dwa_decoder.h
===================================================================
--- openexr-3.2.2.orig/src/lib/OpenEXRCore/internal_dwa_decoder.h
+++ openexr-3.2.2/src/lib/OpenEXRCore/internal_dwa_decoder.h
@@ -265,7 +265,7 @@ LossyDctDecoder_execute (
     }
 
     for (int comp = 1; comp < numComp; ++comp)
-        rowBlock[comp] = rowBlock[comp - 1] + numBlocksX * 64;
+        rowBlock[comp] = rowBlock[comp - 1] + (size_t) numBlocksX * 64;
 
     //
     // Pack DC components together by common plane, so we can get
@@ -275,7 +275,7 @@ LossyDctDecoder_execute (
 
     currDcComp[0] = (uint16_t*) d->_packedDc;
     for (int comp = 1; comp < numComp; ++comp)
-        currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY;
+        currDcComp[comp] = currDcComp[comp - 1] + (size_t) numBlocksX * numBlocksY;
 
     for (int blocky = 0; blocky < numBlocksY; ++blocky)
     {
