8381007: MultiPixelPackedSampleModel can throw ArithmeticException

Reviewed-by: jdv, azvegint, serb
This commit is contained in:
Phil Race 2026-05-29 18:41:55 +00:00
parent 2baa87be25
commit c09e403385
2 changed files with 191 additions and 26 deletions

View File

@ -99,22 +99,39 @@ public class MultiPixelPackedSampleModel extends SampleModel
* either {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_USHORT}, or
* {@code DataBuffer.TYPE_INT}
* @throws IllegalArgumentException if either {@code w} or {@code h}
* is less than or equal to 0
* @throws RasterFormatException if the number of bits per pixel
* is not a power of 2 or if a power of 2 number of
* pixels do not fit in one data element.
*/
public MultiPixelPackedSampleModel(int dataType,
int w,
int h,
int numberOfBits) {
this(dataType,w,h,
numberOfBits,
(w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
DataBuffer.getDataTypeSize(dataType),
0);
long size = (long)w * h;
if (w <= 0 || h <= 0) {
throw new IllegalArgumentException("Width ("+w+") and height ("+
h+") must be > 0");
}
if (size > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Dimensions (width="+w+
" height="+h+") are too large");
}
if (dataType != DataBuffer.TYPE_BYTE &&
dataType != DataBuffer.TYPE_USHORT &&
dataType != DataBuffer.TYPE_INT) {
throw new IllegalArgumentException("Unsupported data type "+
dataType != DataBuffer.TYPE_INT)
{
throw new IllegalArgumentException("Unsupported dataType: "+
dataType);
}
long sls = ((long)w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
DataBuffer.getDataTypeSize(dataType);
if (sls > Integer.MAX_VALUE) {
throw new RasterFormatException("Pixels do not fit");
}
this(dataType, w, h, numberOfBits, (int)sls, 0);
}
/**
@ -130,15 +147,23 @@ public class MultiPixelPackedSampleModel extends SampleModel
* @param scanlineStride the line stride of the image data
* @param dataBitOffset the data bit offset for the region of image
* data described
* @throws RasterFormatException if the number of bits per pixel
* is not a power of 2 or if a power of 2 number of
* pixels do not fit in one data element.
* @throws IllegalArgumentException if {@code w} or
* {@code h} is not greater than 0
* @throws IllegalArgumentException if {@code dataType} is not
* either {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_USHORT}, or
* {@code DataBuffer.TYPE_INT}
* @throws IllegalArgumentException if either {@code w} or {@code h}
* is less than or equal to 0
* @throws IllegalArgumentException if {@code scanlineStride}
* is less than or equal to 0
* @throws RasterFormatException if
* {@code ((numberOfBits * (long)w) + DataBuffer.getDataTypeSize(dataType) - 1)
* / DataBuffer.getDataTypeSize(dataType)}
* is greater than {@code scanlineStride}
* @throws RasterFormatException if the number of bits per pixel
* is not a power of 2 or if a power of 2 number of
* pixels do not fit in one data element.
* @throws IllegalArgumentException if {@code dataBitOffset} is less than zero,
* or not a multiple of {@code numberOfBits}.
*/
public MultiPixelPackedSampleModel(int dataType, int w, int h,
int numberOfBits,
@ -151,11 +176,27 @@ public class MultiPixelPackedSampleModel extends SampleModel
throw new IllegalArgumentException("Unsupported data type "+
dataType);
}
if ((numberOfBits <= 0) || ((numberOfBits & (numberOfBits - 1)) != 0)) {
throw new RasterFormatException("numberOfBits per pixel must be a power of 2");
}
if (scanlineStride <= 0) {
throw new IllegalArgumentException("scanlineStride must be > 0");
}
int dataTypeSize = DataBuffer.getDataTypeSize(dataType);
if ((((numberOfBits * (long)w) + dataTypeSize - 1) / dataTypeSize) > scanlineStride) {
throw new RasterFormatException("scanlineStride is too small for width");
}
if (dataBitOffset < 0) {
throw new IllegalArgumentException("dataBitOffset must be >= 0");
}
if ((dataBitOffset % numberOfBits) != 0) {
throw new IllegalArgumentException("dataBitOffset must be a multiple of bits per pixel");
}
this.dataType = dataType;
this.pixelBitStride = numberOfBits;
this.scanlineStride = scanlineStride;
this.dataBitOffset = dataBitOffset;
this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
this.dataElementSize = dataTypeSize;
this.pixelsPerDataElement = dataElementSize/numberOfBits;
if (pixelsPerDataElement*numberOfBits != dataElementSize) {
throw new RasterFormatException("MultiPixelPackedSampleModel " +
@ -320,22 +361,12 @@ public class MultiPixelPackedSampleModel extends SampleModel
* subset of the bands of this
* {@code MultiPixelPackedSampleModel}. Since a
* {@code MultiPixelPackedSampleModel} only has one band, the
* bands argument must have a length of one and indicate the zeroth
* band.
* @param bands the specified bands
* @return a new {@code SampleModel} with a subset of bands of
* bands argument is ignored.
* @param bands the specified bands (ignored)
* @return a new {@code SampleModel} with the same bands as
* this {@code MultiPixelPackedSampleModel}.
* @throws RasterFormatException if the number of bands requested
* is not one.
* @throws IllegalArgumentException if {@code w} or
* {@code h} is not greater than 0
*/
public SampleModel createSubsetSampleModel(int[] bands) {
if (bands != null) {
if (bands.length != 1)
throw new RasterFormatException("MultiPixelPackedSampleModel has "
+ "only one band.");
}
SampleModel sm = createCompatibleSampleModel(width, height);
return sm;
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static java.awt.image.DataBuffer.TYPE_BYTE;
import static java.awt.image.DataBuffer.TYPE_INT;
import static java.awt.image.DataBuffer.TYPE_SHORT;
import static java.awt.image.DataBuffer.TYPE_USHORT;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.RasterFormatException;
/*
* @test
* @bug 8381007
* @summary test MultiPixelPackedSampleModel Constructors
*/
public class MultiPixelPackedSampleModelConstructor {
public static void main(String[] args) {
for (Args4 a : args4) {
test4(a);
}
for (Args6 a : args6) {
test6(a);
}
// Also verify createSubsetSampleModel ignores bands.
MultiPixelPackedSampleModel m =
new MultiPixelPackedSampleModel(TYPE_BYTE, 1, 1, 1);
int[] bands = new int[5];
m.createSubsetSampleModel(bands);
}
static record Args4(int dType, int w, int h, int bits, Class eType) { }
static final Args4[] args4 = {
new Args4(TYPE_BYTE, 1, 1, -1, RasterFormatException.class),
new Args4(TYPE_BYTE, 1, 1, 0, RasterFormatException.class),
new Args4(TYPE_BYTE, 1, 1, 1, null),
new Args4(TYPE_BYTE, 1, 1, 3, RasterFormatException.class),
new Args4(TYPE_BYTE, 1, 1, 4, null),
new Args4(TYPE_BYTE, 1, 1, 16, RasterFormatException.class),
new Args4(TYPE_BYTE, -1, 1, 1, IllegalArgumentException.class),
new Args4(TYPE_SHORT, -1, 1, 1, IllegalArgumentException.class),
new Args4(TYPE_SHORT, 1, 1, 16, IllegalArgumentException.class),
new Args4(TYPE_USHORT, 1, 1, 16, null),
new Args4(TYPE_INT, 1, 1, 16, null),
new Args4(TYPE_BYTE, 1, 30, 0, RasterFormatException.class),
new Args4(TYPE_BYTE, 0, 1, 4, IllegalArgumentException.class),
new Args4(TYPE_BYTE, 1<<29, 1, 4, null),
new Args4(TYPE_BYTE, 1<<30, 1, 16, RasterFormatException.class),
new Args4(TYPE_BYTE, 32, 1, 1<<30, RasterFormatException.class),
new Args4(99, 8, 1, 1, IllegalArgumentException.class),
};
static record Args6(int dType, int w, int h, int bits, int stride, int bitOffset, Class eType) { }
static final Args6[] args6 = {
new Args6(TYPE_BYTE, 1, 1, -1, 1, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 1, 1, 0, 1, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 1, 1, 1, 1, 0, null),
new Args6(TYPE_BYTE, 1, 1, 3, 1, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 1, 1, 4, 1, 0, null),
new Args6(TYPE_BYTE, 1, 1, 16, 2, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 9, 1, 1, 1, 0, RasterFormatException.class),
new Args6(TYPE_SHORT, 1, 1, 16, 2, 0, IllegalArgumentException.class),
new Args6(TYPE_USHORT, 1, 1, 16, 2, 0, null),
new Args6(TYPE_INT, 1, 1, 16, 1, 0, null),
new Args6(TYPE_BYTE, 1, 30, 0, 4, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 0, 1, 4, 1, 0, IllegalArgumentException.class),
new Args6(TYPE_BYTE, 1, 1, 2, 1, 0, null),
new Args6(TYPE_BYTE, 4, 1, 4, 1, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 1, 1, 2, 1, 1, IllegalArgumentException.class),
new Args6(TYPE_BYTE, 1, 1, 2, 1, -1, IllegalArgumentException.class),
new Args6(TYPE_BYTE, 1, 1, 1, -1, 1, IllegalArgumentException.class),
new Args6(TYPE_BYTE, -1, 1, 1, 1, 1, IllegalArgumentException.class),
new Args6(TYPE_BYTE, 1, 1, 1, 1, 1, null),
new Args6(TYPE_INT, 77777777, 2, 32, 1, 0, RasterFormatException.class),
new Args6(TYPE_BYTE, 1<<29, 1, 4, 1<<28, 0, null),
new Args6(99, 8, 1, 1, 1, 0, IllegalArgumentException.class),
};
static void test4(Args4 a) {
try {
new MultiPixelPackedSampleModel(a.dType, a.w, a.h, a.bits);
} catch (Exception e) {
if (a.eType == null || !(a.eType.isInstance(e))) {
throw new RuntimeException("failed for " + a + " got " + e);
} else {
return;
}
}
if (a.eType != null) {
throw new RuntimeException("No exception for " + a);
}
}
static void test6(Args6 a) {
try {
new MultiPixelPackedSampleModel(a.dType, a.w, a.h, a.bits, a.stride, a.bitOffset);
} catch (Exception e) {
if (a.eType == null || !(a.eType.isInstance(e))) {
throw new RuntimeException("failed for " + a + " got " + e);
} else {
return;
}
}
if (a.eType != null) {
throw new RuntimeException("No exception for " + a);
}
}
}