From cf30b250a4b5b4b5a67162049a25e1f03001160d Mon Sep 17 00:00:00 2001 From: Mark Callow Date: Wed, 20 May 2026 18:55:43 +0900 Subject: [PATCH 1/3] Fix handling of edge tiles. These may not be the full tile width and height. Fixes #1173. --- tools/imageio/exr.imageio/exrinput.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/imageio/exr.imageio/exrinput.cc b/tools/imageio/exr.imageio/exrinput.cc index d1e149dc65..7b601fd2e8 100644 --- a/tools/imageio/exr.imageio/exrinput.cc +++ b/tools/imageio/exr.imageio/exrinput.cc @@ -258,6 +258,8 @@ void ExrInput::readImage(void* outputBuffer, size_t bufferByteCount, " images for each face and use those to create your KTX file."); } } + if (header.tiled && header.tile_level_mode != TINYEXR_TILE_ONE_LEVEL) + throw std::runtime_error(fmt::format("Multi-level tiled EXR images are not supported.")); if ((header.tiled && image.tiles == nullptr) || (!header.tiled && image.images == nullptr)) throw std::runtime_error(fmt::format("Invalid EXR file. {}", header.tiled ? "Tiled with no tiles" : "scanline with no images.")); @@ -297,8 +299,8 @@ void ExrInput::readImage(void* outputBuffer, size_t bufferByteCount, }; for(int32_t tile = 0; tile < image.num_tiles; ++tile) { - for (int32_t ty = 0; ty < header.tile_size_y; ++ty) { - for (int32_t tx = 0; tx < header.tile_size_x; ++tx) { + for (int32_t ty = 0; ty < image.tiles[tile].height; ++ty) { + for (int32_t tx = 0; tx < image.tiles[tile].width; ++tx) { auto x = image.tiles[tile].offset_x * header.tile_size_x + tx; auto y = image.tiles[tile].offset_y * header.tile_size_y + ty; auto* targetPixel = ptr + (y * width * numTargetChannels + x * numTargetChannels) * dataSize; From 9ec1ca0ac272485784aa230091903816b355ee19 Mon Sep 17 00:00:00 2001 From: Mark Callow Date: Fri, 22 May 2026 18:28:31 +0900 Subject: [PATCH 2/3] Add asserts to check for potential buffer overrun. --- tools/imageio/exr.imageio/exrinput.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/imageio/exr.imageio/exrinput.cc b/tools/imageio/exr.imageio/exrinput.cc index 7b601fd2e8..017b243422 100644 --- a/tools/imageio/exr.imageio/exrinput.cc +++ b/tools/imageio/exr.imageio/exrinput.cc @@ -304,6 +304,7 @@ void ExrInput::readImage(void* outputBuffer, size_t bufferByteCount, auto x = image.tiles[tile].offset_x * header.tile_size_x + tx; auto y = image.tiles[tile].offset_y * header.tile_size_y + ty; auto* targetPixel = ptr + (y * width * numTargetChannels + x * numTargetChannels) * dataSize; + assert(targetPixel < ptr + bufferByteCount && "outputBuffer overrun loading tiled .exr"); for (uint32_t c = 0; c < numTargetChannels; ++c) { if (channels[c].has_value()) { std::memcpy(targetPixel + c * dataSize, sourcePtr(*channels[c], tile, tx, ty), dataSize); @@ -325,6 +326,7 @@ void ExrInput::readImage(void* outputBuffer, size_t bufferByteCount, for (uint32_t y = 0; y < height; ++y) { for (uint32_t x = 0; x < width; ++x) { auto* targetPixel = ptr + (y * width * numTargetChannels + x * numTargetChannels) * dataSize; + assert(targetPixel < ptr + bufferByteCount && "outputBuffer overrun loading scanline .exr"); for (uint32_t c = 0; c < numTargetChannels; ++c) { if (channels[c].has_value()) { std::memcpy(targetPixel + c * dataSize, sourcePtr(*channels[c], x, y), dataSize); From 49758b428e9e9117d1a5ecd45ca46af10198f2fd Mon Sep 17 00:00:00 2001 From: Mark Callow Date: Fri, 22 May 2026 18:33:39 +0900 Subject: [PATCH 3/3] Update CTS reference for added subcases. --- tests/cts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts b/tests/cts index c8e3003317..a79b5e9aa0 160000 --- a/tests/cts +++ b/tests/cts @@ -1 +1 @@ -Subproject commit c8e30033171b6c3bd69681796d8f2f6ae2d95322 +Subproject commit a79b5e9aa0142195e08dc4dfcb753429f1a5e50a