From 38d5cdac834476fb7062c0ab9bf4d79e7f3311d8 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 1 Jul 2026 17:21:11 -0400 Subject: [PATCH] fix(cineon): validate bit depth against libcineon's supported set CineonInput::open() accepted any per-channel bit depth in [1,32], but libcineon's ComponentDataSize()/ComponentByteCount() only recognize {8,10,12,16,32,64} and assert(0) on anything else. A crafted file with an unsupported bit depth (e.g. 26) passed the OIIO-side check and then aborted deep inside the vendored library instead of failing cleanly. Tighten the check to libcineon's actual whitelist so bogus bit depths are rejected with a proper errorfmt() before ever reaching the vendored code. Adds a regression fixture (broken_bitdepth2.cin) to the cineon testsuite. Assisted-by: Claude Code / Sonnet 5 Signed-off-by: Larry Gritz --- src/cineon.imageio/cineoninput.cpp | 14 +++++++++++++- testsuite/cineon/ref/out.txt | 3 +++ testsuite/cineon/run.py | 3 +++ testsuite/cineon/src/broken_bitdepth2.cin | Bin 0 -> 2077 bytes 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 testsuite/cineon/src/broken_bitdepth2.cin diff --git a/src/cineon.imageio/cineoninput.cpp b/src/cineon.imageio/cineoninput.cpp index 330ba34c27..48f50e0ff8 100644 --- a/src/cineon.imageio/cineoninput.cpp +++ b/src/cineon.imageio/cineoninput.cpp @@ -102,8 +102,20 @@ CineonInput::open(const std::string& name, ImageSpec& newspec) int maxbits = 0; for (int i = 0; i < nchannels; i++) { int b(m_cin.header.BitDepth(i)); - if (b < 1 || b > 32) { + // libcineon's ComponentDataSize/ComponentByteCount only know how to + // handle these bit depths; anything else asserts (or worse, in a + // non-debug build) deep inside the vendored library. Reject bogus + // values here so we can give a proper error instead. + switch (b) { + case 8: + case 10: + case 12: + case 16: + case 32: + case 64: break; + default: errorfmt("Invalid bitdepth in channel {}: {} bits", i, b); + close(); return false; } maxbits = std::max(maxbits, b); diff --git a/testsuite/cineon/ref/out.txt b/testsuite/cineon/ref/out.txt index 74ad31e404..07f06a1928 100644 --- a/testsuite/cineon/ref/out.txt +++ b/testsuite/cineon/ref/out.txt @@ -36,3 +36,6 @@ Reading ../oiio-images/cineon/checker.cin oiiotool ERROR: read : "src/broken_bitdepth.cin": Invalid number of channels 255 (must be 1-8) Full command line was: > oiiotool --info --hash src/broken_bitdepth.cin +oiiotool ERROR: read : "src/broken_bitdepth2.cin": Invalid bitdepth in channel 0: 26 bits +Full command line was: +> oiiotool --info --hash src/broken_bitdepth2.cin diff --git a/testsuite/cineon/run.py b/testsuite/cineon/run.py index e73803c963..9e01f91ed5 100755 --- a/testsuite/cineon/run.py +++ b/testsuite/cineon/run.py @@ -14,5 +14,8 @@ # Regression tests for broken files command += info_command ("src/broken_bitdepth.cin", verbose=False, failureok=True) +# Regression test for a per-channel bit depth libcineon doesn't recognize +# (used to assert/abort inside CineonHeader.cpp instead of erroring out). +command += info_command ("src/broken_bitdepth2.cin", verbose=False, failureok=True) outputs = [ "out.txt" ] diff --git a/testsuite/cineon/src/broken_bitdepth2.cin b/testsuite/cineon/src/broken_bitdepth2.cin new file mode 100644 index 0000000000000000000000000000000000000000..fdee065778c6e0cb821d9d1e9fdbe140545464a7 GIT binary patch literal 2077 zcmcZ}uhqc7!N9=40>waz5y%fS(K7`y=><43Ey5y%sR-y;pdh0ZghG+8cV=K{utyOZ m15O$GNdN#ns0Mxj literal 0 HcmV?d00001