This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 702aca1a9f use math multiplyexact for multiplication (#1095)
702aca1a9f is described below
commit 702aca1a9ff230291429eaded36c266254624224
Author: PJ Fanning <[email protected]>
AuthorDate: Wed May 27 21:38:54 2026 +0100
use math multiplyexact for multiplication (#1095)
* Use Math.multiplyExact to guard against integer overflow in
multiplications
* int exact
* avoid some casts
* Update Ole10Native.java
* fix test issues
---------
Co-authored-by: copilot-swe-agent[bot]
<[email protected]>
---
.../src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java | 2 +-
.../src/main/java/org/apache/poi/hemf/record/emf/HemfText.java | 3 ++-
.../src/main/java/org/apache/poi/hslf/dev/SlideShowDumper.java | 2 +-
.../src/main/java/org/apache/poi/hwmf/draw/HwmfROP3Composite.java | 2 +-
.../src/main/java/org/apache/poi/hwmf/record/HwmfBitmap16.java | 2 +-
.../src/main/java/org/apache/poi/hwmf/record/HwmfBitmapDib.java | 7 ++++---
.../src/main/java/org/apache/poi/hwpf/model/OldTextPieceTable.java | 2 +-
.../src/main/java/org/apache/poi/hwpf/model/TextPieceTable.java | 2 +-
poi/src/main/java/org/apache/poi/hpsf/Property.java | 4 ++--
.../java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java | 4 ++--
poi/src/main/java/org/apache/poi/poifs/filesystem/Ole10Native.java | 5 +++--
poi/src/main/java/org/apache/poi/ss/formula/functions/Complex.java | 5 +++--
poi/src/main/java/org/apache/poi/util/IOUtils.java | 6 ++++--
.../main/java/org/apache/poi/util/RLEDecompressingInputStream.java | 2 +-
.../test/java/org/apache/poi/poifs/filesystem/TestPOIFSStream.java | 2 +-
test-data/poi-integration-exceptions.csv | 2 +-
16 files changed, 29 insertions(+), 23 deletions(-)
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java
index cb9ab2ebc5..01b43d613f 100644
---
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java
+++
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java
@@ -173,7 +173,7 @@ public class HemfHeader implements HemfRecord {
if (skip < 0 || descriptionEnd > recordSize + HEADER_SIZE || skip
+ descriptionBytes > Integer.MAX_VALUE) {
throw new RecordFormatException("Invalid EMF header
description bounds");
}
- int maxDescriptionLength = (int)Math.min(recordSize,
Integer.MAX_VALUE);
+ int maxDescriptionLength = Math.toIntExact(Math.min(recordSize,
Integer.MAX_VALUE));
IOUtils.safelyAllocateCheck(descriptionBytes,
maxDescriptionLength);
leis.mark((int)(skip + descriptionBytes));
leis.skipFully((int)skip);
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfText.java
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfText.java
index 3b6aaddd75..efe73fdf90 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfText.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfText.java
@@ -156,7 +156,8 @@ public class HemfText {
//
// If ETO_RTLREADING is specified, characters are
laid right to left instead of left to right.
// No other options affect the interpretation of
this field.
- final int maxSize = (int)Math.min((offDx <
offString) ? (offString-HEADER_SIZE) : recordSize, recordSize);
+ final int maxSize = Math.toIntExact(Math.min(
+ offDx < offString ?
(offString-HEADER_SIZE) : recordSize, recordSize));
while (size <=
maxSize-LittleEndianConsts.INT_SIZE) {
dx.add((int) leis.readUInt());
size += LittleEndianConsts.INT_SIZE;
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowDumper.java
b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowDumper.java
index 8b43555d07..cbaa53c824 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowDumper.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowDumper.java
@@ -224,7 +224,7 @@ public final class SlideShowDumper {
}
}
- pos += (int) Math.min(len, Integer.MAX_VALUE);
+ pos += Math.toIntExact(Math.min(len, Integer.MAX_VALUE));
}
}
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/draw/HwmfROP3Composite.java
b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/draw/HwmfROP3Composite.java
index 6cac2a5dca..b176aedbab 100644
---
a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/draw/HwmfROP3Composite.java
+++
b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/draw/HwmfROP3Composite.java
@@ -56,7 +56,7 @@ public class HwmfROP3Composite implements Composite {
} else {
mask_width = bitmap.getWidth();
mask_height = bitmap.getHeight();
- mask = new byte[mask_width * mask_height];
+ mask = new byte[Math.multiplyExact(mask_width, mask_height)];
bitmap.getRaster().getDataElements(0, 0, mask_width, mask_height,
mask);
}
this.background = background.getRGB();
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmap16.java
b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmap16.java
index cc103b2c06..cb8315d8ce 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmap16.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmap16.java
@@ -79,7 +79,7 @@ public class HwmfBitmap16 implements GenericRecord {
size += 18+LittleEndianConsts.INT_SIZE;
}
- int length = (((width * bitsPixel + 15) >> 4) << 1) * height;
+ int length = Math.multiplyExact(((width * bitsPixel + 15) >> 4) << 1,
height);
bitmap = IOUtils.toByteArray(leis, length);
// TODO: this is not implemented ... please provide a sample, if it
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmapDib.java
b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmapDib.java
index cfe5804ee3..4a82faf123 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmapDib.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hwmf/record/HwmfBitmapDib.java
@@ -246,8 +246,8 @@ public class HwmfBitmapDib implements GenericRecord {
// The size and format of this data is determined by information in
the DIBHeaderInfo field. If
// it is a BitmapCoreHeader, the size in bytes MUST be calculated as
follows:
- int bodySize = ((((headerWidth * headerPlanes *
- (headerBitCount == null ? 0 : headerBitCount.flag) + 31) &
~31) / 8) * Math.abs(headerHeight));
+ long bodySize = ((((long)headerWidth * headerPlanes *
+ (headerBitCount == null ? 0 : headerBitCount.flag) + 31L) &
~31L) / 8L) * Math.abs((long)headerHeight);
// This formula SHOULD also be used to calculate the size of aData
when DIBHeaderInfo is a
// BitmapInfoHeader Object, using values from that object, but only if
its Compression value is
@@ -260,7 +260,8 @@ public class HwmfBitmapDib implements GenericRecord {
headerCompression == Compression.BI_RGB ||
headerCompression == Compression.BI_BITFIELDS ||
headerCompression == Compression.BI_CMYK) {
- int fileSize = Math.min(introSize+bodySize,recordSize);
+ int fileSize = Math.toIntExact(
+ Math.min(introSize + bodySize, recordSize));
imageData = IOUtils.safelyAllocate(fileSize,
HwmfPicture.getMaxRecordLength());
leis.readFully(imageData, 0, introSize);
leis.skipFully(recordSize-fileSize);
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/OldTextPieceTable.java
b/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/OldTextPieceTable.java
index 384803469e..f82fd32eff 100644
---
a/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/OldTextPieceTable.java
+++
b/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/OldTextPieceTable.java
@@ -77,7 +77,7 @@ public class OldTextPieceTable extends TextPieceTable {
// Figure out the length, in bytes and chars
int textSizeChars = (nodeEndChars - nodeStartChars);
- int textSizeBytes = textSizeChars * multiple;
+ int textSizeBytes = Math.multiplyExact(textSizeChars, multiple);
// Grab the data that makes up the piece
byte[] buf = IOUtils.safelyClone(documentStream, start,
textSizeBytes, getMaxRecordLength());
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/TextPieceTable.java
b/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/TextPieceTable.java
index e011f7f819..aa02c1bf1e 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/TextPieceTable.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/TextPieceTable.java
@@ -112,7 +112,7 @@ public class TextPieceTable implements CharIndexTranslator {
// Figure out the length, in bytes and chars
int textSizeChars = (nodeEndChars - nodeStartChars);
- int textSizeBytes = textSizeChars * multiple;
+ int textSizeBytes = Math.multiplyExact(textSizeChars, multiple);
// Grab the data that makes up the piece
byte[] buf = IOUtils.safelyClone(documentStream, start,
textSizeBytes, MAX_RECORD_LENGTH);
diff --git a/poi/src/main/java/org/apache/poi/hpsf/Property.java
b/poi/src/main/java/org/apache/poi/hpsf/Property.java
index fa336345e5..410f517e6d 100644
--- a/poi/src/main/java/org/apache/poi/hpsf/Property.java
+++ b/poi/src/main/java/org/apache/poi/hpsf/Property.java
@@ -145,7 +145,7 @@ public class Property {
o += LittleEndianConsts.INT_SIZE;
try {
- value = VariantSupport.read(src, o, length, (int) type, codepage);
+ value = VariantSupport.read(src, o, length, Math.toIntExact(type),
codepage);
} catch (UnsupportedVariantTypeException ex) {
VariantSupport.writeUnsupportedTypeMessage(ex);
value = ex.getValue();
@@ -179,7 +179,7 @@ public class Property {
type = leis.readUInt();
try {
- value = VariantSupport.read(leis, length, (int) type, codepage);
+ value = VariantSupport.read(leis, length, Math.toIntExact(type),
codepage);
} catch (UnsupportedVariantTypeException ex) {
VariantSupport.writeUnsupportedTypeMessage(ex);
value = ex.getValue();
diff --git
a/poi/src/main/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java
b/poi/src/main/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java
index baa2a000df..e75e598e66 100644
--- a/poi/src/main/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java
+++ b/poi/src/main/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java
@@ -104,7 +104,7 @@ public abstract class ChunkedCipherInputStream extends
LittleEndianInputStream {
throw new EncryptedDocumentException(e.getMessage(), e);
}
}
- int count = (int)(chunk.length - (pos & chunkMask));
+ int count = Math.toIntExact(chunk.length - (pos & chunkMask));
int avail = remainingBytes();
if (avail == 0) {
return total;
@@ -185,7 +185,7 @@ public abstract class ChunkedCipherInputStream extends
LittleEndianInputStream {
lastIndex = index + 1;
}
- final int todo = (int)Math.min(size, chunk.length);
+ final int todo = Math.toIntExact(Math.min(size, chunk.length));
int readBytes, totalBytes = 0;
do {
readBytes = super.read(plain, totalBytes, todo-totalBytes);
diff --git a/poi/src/main/java/org/apache/poi/poifs/filesystem/Ole10Native.java
b/poi/src/main/java/org/apache/poi/poifs/filesystem/Ole10Native.java
index 027500dcb5..d59b129128 100644
--- a/poi/src/main/java/org/apache/poi/poifs/filesystem/Ole10Native.java
+++ b/poi/src/main/java/org/apache/poi/poifs/filesystem/Ole10Native.java
@@ -289,8 +289,9 @@ public class Ole10Native {
}
private static String readUtf16(LittleEndianByteArrayInputStream leis)
throws IOException {
- int size = leis.readInt();
- byte[] buf = IOUtils.toByteArray(leis, size * 2L, MAX_STRING_LENGTH);
+ final int size = leis.readInt();
+ final long arraySize = 2L * size;
+ final byte[] buf = IOUtils.toByteArray(leis, arraySize,
MAX_STRING_LENGTH);
return StringUtil.getFromUnicodeLE(buf, 0, size);
}
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Complex.java
b/poi/src/main/java/org/apache/poi/ss/formula/functions/Complex.java
index a4fac2685e..99362bed8c 100644
--- a/poi/src/main/java/org/apache/poi/ss/formula/functions/Complex.java
+++ b/poi/src/main/java/org/apache/poi/ss/formula/functions/Complex.java
@@ -25,6 +25,7 @@ import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.util.MathUtil;
/**
* Implementation for Excel COMPLEX () function.
@@ -104,7 +105,7 @@ public class Complex extends Var2or3ArgFunction implements
FreeRefFunction {
StringBuilder strb = new StringBuilder();
if (realNum != 0) {
if (isDoubleAnInt(realNum)) {
- strb.append((int)realNum);
+ strb.append(MathUtil.safeDoubleToInt(realNum));
} else {
strb.append(realNum);
}
@@ -118,7 +119,7 @@ public class Complex extends Var2or3ArgFunction implements
FreeRefFunction {
if (realINum != 1 && realINum != -1) {
if (isDoubleAnInt(realINum)) {
- strb.append((int)realINum);
+ strb.append(MathUtil.safeDoubleToInt(realINum));
} else {
strb.append(realINum);
}
diff --git a/poi/src/main/java/org/apache/poi/util/IOUtils.java
b/poi/src/main/java/org/apache/poi/util/IOUtils.java
index 2ebbd69e32..1b2d413d5e 100644
--- a/poi/src/main/java/org/apache/poi/util/IOUtils.java
+++ b/poi/src/main/java/org/apache/poi/util/IOUtils.java
@@ -232,8 +232,10 @@ public final class IOUtils {
* @since 5.4.1
*/
public static byte[] toByteArray(InputStream stream, final long length,
final int maxLength) throws IOException {
- return toByteArray(stream,
- length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length,
+ if (length > Integer.MAX_VALUE) {
+ throwRFE(length, maxLength);
+ }
+ return toByteArray(stream, Math.toIntExact(length),
maxLength, true, length != Integer.MAX_VALUE);
}
diff --git
a/poi/src/main/java/org/apache/poi/util/RLEDecompressingInputStream.java
b/poi/src/main/java/org/apache/poi/util/RLEDecompressingInputStream.java
index 8a6b9bff82..3c883d0ed2 100644
--- a/poi/src/main/java/org/apache/poi/util/RLEDecompressingInputStream.java
+++ b/poi/src/main/java/org/apache/poi/util/RLEDecompressingInputStream.java
@@ -131,7 +131,7 @@ public class RLEDecompressingInputStream extends
InputStream {
return -1;
}
}
- int c = (int) Math.min(n, len - (long)pos);
+ int c = Math.toIntExact(Math.min(n, len - pos));
pos += c;
length -= c;
}
diff --git
a/poi/src/test/java/org/apache/poi/poifs/filesystem/TestPOIFSStream.java
b/poi/src/test/java/org/apache/poi/poifs/filesystem/TestPOIFSStream.java
index 9dd6043ae1..756df2f78e 100644
--- a/poi/src/test/java/org/apache/poi/poifs/filesystem/TestPOIFSStream.java
+++ b/poi/src/test/java/org/apache/poi/poifs/filesystem/TestPOIFSStream.java
@@ -2725,7 +2725,7 @@ final class TestPOIFSStream {
@Override
public int read(byte[] b, int offset, int len) {
if (size >= maxSize) return -1;
- int sz = (int) Math.min(len, maxSize - size);
+ int sz = Math.toIntExact(Math.min(len, maxSize - size));
for (int i = 0; i < sz; i++) {
b[i + offset] = (byte) ((size + i) % 128);
}
diff --git a/test-data/poi-integration-exceptions.csv
b/test-data/poi-integration-exceptions.csv
index c3f2806697..e0849f0a0b 100644
--- a/test-data/poi-integration-exceptions.csv
+++ b/test-data/poi-integration-exceptions.csv
@@ -100,7 +100,7 @@
spreadsheet/sample.strict.xlsx,extract,OPC,,org.apache.poi.ooxml.POIXMLException
spreadsheet/57914.xlsx,"handle,extract",XSSF,,org.apache.poi.ooxml.POIXMLException,"Strict
OOXML isn't currently supported, please see bug #57699",
spreadsheet/57914.xlsx,extract,OPC,,org.apache.poi.ooxml.POIXMLException,"Strict
OOXML isn't currently supported, please see bug #57699",
spreadsheet/poi-fuzz.xls,additional,HSSF,,org.apache.poi.util.RecordFormatException,Not
enough data (0) to read requested (4) bytes,
-spreadsheet/poi-fuzz.xls,additional,HPSF,,org.apache.poi.util.RecordFormatException,Overflow
when calculating the number of scalar values,
+spreadsheet/poi-fuzz.xls,additional,HPSF,,java.lang.ArithmeticException,integer
overflow,
spreadsheet/poi-fuzz.xls,handle,HPSF,,org.opentest4j.AssertionFailedError,expected:
<true> but was: <false>,
openxml4j/ContentTypeHasEntities.ooxml,"handle,extract",OPC,,org.apache.poi.openxml4j.exceptions.InvalidFormatException,Can't
read content types part !,
ddf/Container.dat,handle,HMEF,,java.lang.IllegalArgumentException,"TNEF
signature not detected in file, expected 574529400 but got -268435441",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]