From a27d0dc18bdef041bafc3a34b2f4591eadee20af Mon Sep 17 00:00:00 2001 From: Sharang Gupta Date: Tue, 13 Oct 2026 18:39:39 +0100 Subject: [PATCH] [IMAGING-386] TiffField numeric getters throw ImagingException for non-number values TiffField.getIntValue() cast the field value to Number without checking it. A BYTE field whose count is not 1 holds a byte[], so a malformed TIFF that declares FillOrder that way made Imaging.getBufferedImage() fail with a ClassCastException instead of the documented ImagingException. Check the type once in a private getNumberValue() and use it from getIntValue(), getLongValue() and getDoubleValue(), which had the same unchecked cast. The null check and the returned values are unchanged. --- src/changes/changes.xml | 1 + .../imaging/formats/tiff/TiffField.java | 30 +++--- .../imaging/formats/tiff/TiffFieldTest.java | 89 ++++++++++++++++++ ...f4bb78375b6353270d3c220d17d6101f916eab.tif | Bin 0 -> 438 bytes 4 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/apache/commons/imaging/formats/tiff/TiffFieldTest.java create mode 100644 src/test/resources/images/tiff/IMAGING-386/crash-46f4bb78375b6353270d3c220d17d6101f916eab.tif diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 201c655091..b53dba7538 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -52,6 +52,7 @@ The type attribute can be add,update,fix,remove. Fix Javadoc warnings. Fix int overflow in PCX image buffer sizing, now throws AllocationRequestException (#552). Fix int overflow in Allocator.array/arrayList size checks (#551). + TiffField.getIntValue(), getLongValue() and getDoubleValue() throw ImagingException instead of ClassCastException when the value is not a single number. Add messages when throwing NullPointerException. Add unit tests (#553). diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffField.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffField.java index e10971f0a8..f6848772d5 100644 --- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffField.java +++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffField.java @@ -248,12 +248,7 @@ public double[] getDoubleArrayValue() throws ImagingException { * @throws ImagingException if the value is missing or cannot be converted. */ public double getDoubleValue() throws ImagingException { - final Object o = getValue(); - if (o == null) { - throw new ImagingException("Missing value: " + getTagInfo().getDescription()); - } - - return ((Number) o).doubleValue(); + return getNumberValue().doubleValue(); } /** @@ -324,12 +319,7 @@ public int[] getIntArrayValue() throws ImagingException { * @throws ImagingException if the value is missing or cannot be converted. */ public int getIntValue() throws ImagingException { - final Object o = getValue(); - if (o == null) { - throw new ImagingException("Missing value: " + getTagInfo().getDescription()); - } - - return ((Number) o).intValue(); + return getNumberValue().intValue(); } /** @@ -419,11 +409,25 @@ public long[] getLongArrayValue() throws ImagingException { * @throws ImagingException if the field instance is of an incompatible type or does not contain a valid data element. */ public long getLongValue() throws ImagingException { + return getNumberValue().longValue(); + } + + /** + * Gets the field value as a single number. + * + * @return The number value. + * @throws ImagingException if the value is missing or is not a single number, for example the {@code byte[]} that a BYTE field holds when its count is + * not 1. + */ + private Number getNumberValue() throws ImagingException { final Object o = getValue(); if (o == null) { throw new ImagingException("Missing value: " + getTagInfo().getDescription()); } - return ((Number) o).longValue(); + if (!(o instanceof Number)) { + throw new ImagingException("Expected a single number for " + getTagInfo().getDescription() + " but the value is a " + o.getClass().getSimpleName()); + } + return (Number) o; } /** diff --git a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFieldTest.java b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFieldTest.java new file mode 100644 index 0000000000..87cbbd7a36 --- /dev/null +++ b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFieldTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.imaging.formats.tiff; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.nio.ByteOrder; + +import org.apache.commons.imaging.Imaging; +import org.apache.commons.imaging.ImagingException; +import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants; +import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants; +import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldTypeByte; +import org.apache.commons.imaging.test.TestResources; +import org.junit.jupiter.api.Test; + +/** + * Tests for the single-value getters of {@link TiffField}. + *

+ * A field with a BYTE type and a count other than 1 has a {@code byte[]} value. The getters document that they throw an {@link ImagingException} when the + * value cannot be converted, so a value that is not a number must not surface as a {@link ClassCastException}. + *

+ */ +class TiffFieldTest { + + /** A FillOrder field (which the specification defines as a single SHORT) that a malformed file declares as BYTE with a count of zero. */ + private static TiffField byteArrayField() { + return new TiffField(TiffTagConstants.TIFF_TAG_FILL_ORDER.tag, TiffDirectoryConstants.DIRECTORY_TYPE_ROOT, new FieldTypeByte(1, "Byte"), 0, 0, + new byte[0], ByteOrder.LITTLE_ENDIAN, 0); + } + + private static TiffField byteField() { + return new TiffField(TiffTagConstants.TIFF_TAG_FILL_ORDER.tag, TiffDirectoryConstants.DIRECTORY_TYPE_ROOT, new FieldTypeByte(1, "Byte"), 1, 0, + new byte[] { 2 }, ByteOrder.LITTLE_ENDIAN, 0); + } + + @Test + void testGetDoubleValueRejectsNonNumber() { + assertThrows(ImagingException.class, () -> byteArrayField().getDoubleValue()); + } + + /** + * For https://issues.apache.org/jira/browse/IMAGING-386. + *

+ * The file declares its FillOrder tag as a BYTE with a count of zero. {@code Imaging.getBufferedImage} is documented to throw {@link ImagingException}, + * not a {@link ClassCastException}. + *

+ */ + @Test + void testGetBufferedImageWithNonNumericFillOrder() { + final File tiff = TestResources.resourceToFile("/images/tiff/IMAGING-386/crash-46f4bb78375b6353270d3c220d17d6101f916eab.tif"); + assertThrows(ImagingException.class, () -> Imaging.getBufferedImage(tiff)); + } + + @Test + void testGetIntValueRejectsNonNumber() { + assertThrows(ImagingException.class, () -> byteArrayField().getIntValue()); + } + + @Test + void testGetLongValueRejectsNonNumber() { + assertThrows(ImagingException.class, () -> byteArrayField().getLongValue()); + } + + @Test + void testNumericValues() throws ImagingException { + final TiffField field = byteField(); + assertEquals(2, field.getIntValue()); + assertEquals(2L, field.getLongValue()); + assertEquals(2.0, field.getDoubleValue()); + } +} diff --git a/src/test/resources/images/tiff/IMAGING-386/crash-46f4bb78375b6353270d3c220d17d6101f916eab.tif b/src/test/resources/images/tiff/IMAGING-386/crash-46f4bb78375b6353270d3c220d17d6101f916eab.tif new file mode 100644 index 0000000000000000000000000000000000000000..766860ff7e38f2bf17bc9c05500c573c82a046c9 GIT binary patch literal 438 zcma)2K?=e!5Zr01wu%rHTMz@Dz3B(^nuCXa$d~w6o!z8T1R(=~*<~`xOpIq~L}Vv| zT0l1ALFQO-$WWDoGmYxznUh{H*|!tEgenP|u2I=bYOu-vC-QC9*Ocv*KfV~aQiCqZ zJ)Ru;@o(fu)xSvMPmFg$tC4QzQ6UszQK&023&B~RV|NFp(LmOnh9R#1%S&Z5{hgP* J-R#9P{|DTR9jpKV literal 0 HcmV?d00001