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 5fc26e44e9 refactor hssf limit code (#1115)
5fc26e44e9 is described below

commit 5fc26e44e95caa43ef5686e0de5eb4042333a2ef
Author: PJ Fanning <[email protected]>
AuthorDate: Thu Jun 4 19:11:36 2026 +0100

    refactor hssf limit code (#1115)
    
    * refactor hssf limit code
    
    * refactor
    
    * revert some changes
    
    * Update IOUtils.java
    
    * Update poi-integration-exceptions.csv
    
    * Update poi-integration-exceptions.csv
---
 .../poi/hssf/extractor/OldExcelExtractor.java      |  2 +-
 .../org/apache/poi/hssf/record/CFRule12Record.java |  8 +--
 .../org/apache/poi/hssf/record/DConRefRecord.java  |  3 +-
 .../hssf/record/EmbeddedObjectRefSubRecord.java    |  3 +-
 .../apache/poi/hssf/record/EscherAggregate.java    |  3 +-
 .../apache/poi/hssf/record/FtCblsSubRecord.java    |  5 +-
 .../poi/hssf/record/GroupMarkerSubRecord.java      |  3 +-
 .../apache/poi/hssf/record/HyperlinkRecord.java    |  3 +-
 .../poi/hssf/record/NoteStructureSubRecord.java    |  5 +-
 .../org/apache/poi/hssf/record/OldLabelRecord.java |  3 +-
 .../org/apache/poi/hssf/record/OldSheetRecord.java |  3 +-
 .../apache/poi/hssf/record/OldStringRecord.java    |  4 +-
 .../org/apache/poi/hssf/record/RecordFactory.java  |  3 +-
 .../apache/poi/hssf/record/RecordInputStream.java  |  3 +-
 .../java/org/apache/poi/hssf/record/SubRecord.java |  3 +-
 .../apache/poi/hssf/record/WriteAccessRecord.java  | 11 ++--
 .../hssf/record/aggregates/SharedValueManager.java | 16 ++++--
 .../org/apache/poi/hssf/record/common/ExtRst.java  |  3 +-
 .../hssf/record/crypto/Biff8DecryptingStream.java  |  3 +-
 .../apache/poi/hssf/usermodel/HSSFWorkbook.java    |  9 +++-
 .../main/java/org/apache/poi/util/ArrayUtil.java   | 16 +++---
 poi/src/main/java/org/apache/poi/util/IOUtils.java | 63 +++++++++++++++-------
 test-data/poi-integration-exceptions.csv           |  6 +--
 23 files changed, 109 insertions(+), 72 deletions(-)

diff --git 
a/poi/src/main/java/org/apache/poi/hssf/extractor/OldExcelExtractor.java 
b/poi/src/main/java/org/apache/poi/hssf/extractor/OldExcelExtractor.java
index 10ab25f188..99f9581865 100644
--- a/poi/src/main/java/org/apache/poi/hssf/extractor/OldExcelExtractor.java
+++ b/poi/src/main/java/org/apache/poi/hssf/extractor/OldExcelExtractor.java
@@ -305,7 +305,7 @@ public class OldExcelExtractor implements POITextExtractor {
                     break;
 
                 default:
-                    ris.readFully(IOUtils.safelyAllocate(ris.remaining(), 
HSSFWorkbook.getMaxRecordLength()));
+                    
ris.readFully(HSSFWorkbook.safelyAllocate(ris.remaining()));
             }
         }
 
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/CFRule12Record.java 
b/poi/src/main/java/org/apache/poi/hssf/record/CFRule12Record.java
index 2b0fb59c5e..0c04ab12f9 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/CFRule12Record.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/CFRule12Record.java
@@ -33,6 +33,7 @@ import org.apache.poi.hssf.record.common.ExtendedColor;
 import org.apache.poi.hssf.record.common.FtrHeader;
 import org.apache.poi.hssf.record.common.FutureRecord;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.formula.Formula;
 import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
@@ -42,7 +43,6 @@ import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianOutput;
 
 import static org.apache.logging.log4j.util.Unbox.box;
-import static org.apache.poi.hssf.usermodel.HSSFWorkbook.getMaxRecordLength;
 
 /**
  * Conditional Formatting v12 Rule Record (0x087A).
@@ -121,7 +121,7 @@ public final class CFRule12Record extends CFRuleBase 
implements FutureRecord {
         priority = 0;
         template_type = getConditionType();
         template_param_length = 16;
-        template_params = IOUtils.safelyAllocate(template_param_length, 
getMaxRecordLength());
+        template_params = HSSFWorkbook.safelyAllocate(template_param_length);
     }
 
     /**
@@ -265,7 +265,7 @@ public final class CFRule12Record extends CFRuleBase 
implements FutureRecord {
         } else {
             long len = readFormatOptions(in);
             if (len < ext_formatting_length) {
-                ext_formatting_data = 
IOUtils.safelyAllocate(ext_formatting_length-len, getMaxRecordLength());
+                ext_formatting_data = 
HSSFWorkbook.safelyAllocate(ext_formatting_length-len);
                 in.readFully(ext_formatting_data);
             }
         }
@@ -281,7 +281,7 @@ public final class CFRule12Record extends CFRuleBase 
implements FutureRecord {
         template_type = in.readUShort();
         template_param_length = in.readByte();
         if (template_param_length == 0 || template_param_length == 16) {
-            template_params = IOUtils.safelyAllocate(template_param_length, 
getMaxRecordLength());
+            template_params = 
HSSFWorkbook.safelyAllocate(template_param_length);
             in.readFully(template_params);
         } else {
             LOG.atWarn().log("CF Rule v12 template params length should be 0 
or 16, found {}", box(template_param_length));
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/DConRefRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/DConRefRecord.java
index 74a6dee371..c72ea13083 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/DConRefRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/DConRefRecord.java
@@ -26,7 +26,6 @@ import java.util.function.Supplier;
 import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.StringUtil;
@@ -157,7 +156,7 @@ public class DConRefRecord extends StandardRecord {
         // single-byte, 1 if double-byte.
         final int byteLength = charCount * (charType + 1);
 
-        path = IOUtils.safelyAllocate(byteLength, 
HSSFWorkbook.getMaxRecordLength());
+        path = HSSFWorkbook.safelyAllocate(byteLength);
         inStream.readFully(path);
 
         // If it's a self reference, the last one or two bytes (depending on 
char type) are the
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
index e5db7b6e67..53930b3b8b 100644
--- 
a/poi/src/main/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
+++ 
b/poi/src/main/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
@@ -31,7 +31,6 @@ import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.ss.formula.ptg.Ref3DPtg;
 import org.apache.poi.ss.formula.ptg.RefPtg;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianInputStream;
@@ -201,7 +200,7 @@ public final class EmbeddedObjectRefSubRecord extends 
SubRecord {
         if (size == 0) {
             return EMPTY_BYTE_ARRAY;
         }
-        byte[] result = IOUtils.safelyAllocate(size, 
HSSFWorkbook.getMaxRecordLength());
+        byte[] result = HSSFWorkbook.safelyAllocate(size);
         in.readFully(result);
         return result;
     }
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/EscherAggregate.java 
b/poi/src/main/java/org/apache/poi/hssf/record/EscherAggregate.java
index fc6d8270b9..d4a882b243 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/EscherAggregate.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/EscherAggregate.java
@@ -364,7 +364,8 @@ public final class EscherAggregate extends 
AbstractEscherHolderRecord {
         // Determine buffer size
         List<EscherRecord> records = getEscherRecords();
         int rawEscherSize = getEscherRecordSize(records);
-        byte[] buffer = IOUtils.safelyAllocate(rawEscherSize, 
MAX_RECORD_LENGTH);
+        byte[] buffer = IOUtils.safelyAllocate(rawEscherSize, 
MAX_RECORD_LENGTH,
+                "EscherAggregate.setMaxRecordLength()");
         final List<Integer> spEndingOffsets = new ArrayList<>();
         int pos = 0;
         for (EscherRecord e : records) {
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/FtCblsSubRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/FtCblsSubRecord.java
index c849ec4f8f..6f4a7e9751 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/FtCblsSubRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/FtCblsSubRecord.java
@@ -20,8 +20,8 @@ package org.apache.poi.hssf.record;
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.poi.util.ArrayUtil;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
@@ -57,7 +57,8 @@ public final class FtCblsSubRecord extends SubRecord {
             throw new RecordFormatException("Unexpected size (" + size + ")");
         }
         //just grab the raw data
-        byte[] buf = IOUtils.safelyAllocate(size, ENCODED_SIZE);
+        ArrayUtil.strictAllocateCheck(size, ENCODED_SIZE);
+        byte[] buf = new byte[size];
         in.readFully(buf);
         reserved = buf;
     }
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
index 64c751a22d..da991817d6 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
@@ -22,7 +22,6 @@ import java.util.function.Supplier;
 
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 
@@ -52,7 +51,7 @@ public final class GroupMarkerSubRecord extends SubRecord {
     }
 
     GroupMarkerSubRecord(LittleEndianInput in, int size, int cmoOt) {
-        byte[] buf = IOUtils.safelyAllocate(size, 
HSSFWorkbook.getMaxRecordLength());
+        byte[] buf = HSSFWorkbook.safelyAllocate(size);
         in.readFully(buf);
         reserved = buf;
     }
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/HyperlinkRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/HyperlinkRecord.java
index a27a9ab82a..4bb17bdbb5 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/HyperlinkRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/HyperlinkRecord.java
@@ -35,7 +35,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.HexRead;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
@@ -389,7 +388,7 @@ public final class HyperlinkRecord extends StandardRecord {
 
                 int len = in.readInt();
 
-                byte[] path_bytes = IOUtils.safelyAllocate(len, 
HSSFWorkbook.getMaxRecordLength());
+                byte[] path_bytes = HSSFWorkbook.safelyAllocate(len);
                 in.readFully(path_bytes);
 
                 _address = new String(path_bytes, StringUtil.UTF8);
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
index e15e05a92f..4dc31ff1e1 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
@@ -20,8 +20,8 @@ package org.apache.poi.hssf.record;
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.poi.util.ArrayUtil;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
@@ -68,7 +68,8 @@ public final class NoteStructureSubRecord extends SubRecord {
             throw new RecordFormatException("Unexpected size (" + size + ")");
         }
         //just grab the raw data
-        byte[] buf = IOUtils.safelyAllocate(size, ENCODED_SIZE);
+        ArrayUtil.strictAllocateCheck(size, ENCODED_SIZE);
+        byte[] buf = new byte[size];
         in.readFully(buf);
         reserved = buf;
     }
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/OldLabelRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/OldLabelRecord.java
index 66fa67f9a9..ad30b9a8aa 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/OldLabelRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/OldLabelRecord.java
@@ -24,7 +24,6 @@ import org.apache.logging.log4j.Logger;
 import org.apache.poi.logging.PoiLogManager;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.RecordFormatException;
 
 import static org.apache.logging.log4j.util.Unbox.box;
@@ -59,7 +58,7 @@ public final class OldLabelRecord extends OldCellRecord {
         }
 
         // Can only decode properly later when you know the codepage
-        field_5_bytes = IOUtils.safelyAllocate(field_4_string_len, 
HSSFWorkbook.getMaxRecordLength());
+        field_5_bytes = HSSFWorkbook.safelyAllocate(field_4_string_len);
         in.read(field_5_bytes, 0, field_4_string_len);
 
         if (in.remaining() > 0) {
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/OldSheetRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/OldSheetRecord.java
index 24f67bf8b9..cd1cc9e7db 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/OldSheetRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/OldSheetRecord.java
@@ -25,7 +25,6 @@ import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.GenericRecordJsonWriter;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.RecordFormatException;
 
 /**
@@ -62,7 +61,7 @@ public final class OldSheetRecord implements GenericRecord {
                 }
             }
         }
-        field_5_sheetname = IOUtils.safelyAllocate(field_4_sheetname_length, 
HSSFWorkbook.getMaxRecordLength());
+        field_5_sheetname = 
HSSFWorkbook.safelyAllocate(field_4_sheetname_length);
         in.read(field_5_sheetname, 0, field_4_sheetname_length);
     }
 
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/OldStringRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/OldStringRecord.java
index 91a00265ff..96ecdd0fbb 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/OldStringRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/OldStringRecord.java
@@ -27,8 +27,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.CodePageUtil;
 import org.apache.poi.util.GenericRecordJsonWriter;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
-
 
 /**
  * Biff2 - Biff 4 Label Record (0x0007 / 0x0207) - read only support for
@@ -57,7 +55,7 @@ public final class OldStringRecord implements GenericRecord {
         }
 
         // Can only decode properly later when you know the codepage
-        field_2_bytes = IOUtils.safelyAllocate(field_1_string_len, 
HSSFWorkbook.getMaxRecordLength());
+        field_2_bytes = HSSFWorkbook.safelyAllocate(field_1_string_len);
         in.read(field_2_bytes, 0, field_1_string_len);
     }
 
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/RecordFactory.java 
b/poi/src/main/java/org/apache/poi/hssf/record/RecordFactory.java
index f0f1c42f82..8d4ff09b19 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/RecordFactory.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/RecordFactory.java
@@ -199,7 +199,8 @@ public final class RecordFactory {
         while ((record = recStream.nextRecord()) != null) {
             records.add(record);
 
-            IOUtils.safelyAllocateCheck(records.size(), MAX_NUMBER_OF_RECORDS);
+            IOUtils.safelyAllocateCheck(records.size(), MAX_NUMBER_OF_RECORDS,
+                    "RecordFactory.setMaxNumberOfRecords");
         }
 
         return records;
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java 
b/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java
index 561768f32b..2ca1740f89 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java
@@ -25,7 +25,6 @@ import 
org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
 import org.apache.poi.hssf.record.crypto.Biff8DecryptingStream;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInput;
@@ -437,7 +436,7 @@ public final class RecordInputStream implements 
LittleEndianInput {
         if (size ==0) {
             return EMPTY_BYTE_ARRAY;
         }
-        byte[] result = IOUtils.safelyAllocate(size, 
HSSFWorkbook.getMaxRecordLength());
+        byte[] result = HSSFWorkbook.safelyAllocate(size);
         readFully(result);
         return result;
     }
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/SubRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/SubRecord.java
index ca16540ec8..07e57f5ef8 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/SubRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/SubRecord.java
@@ -167,7 +167,8 @@ public abstract class SubRecord implements Duplicatable, 
GenericRecord {
 
         public UnknownSubRecord(LittleEndianInput in, int size, int sid) {
             _sid = sid;
-            byte[] buf = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH);
+            byte[] buf = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH,
+                    "SubRecord.setMaxRecordLength");
             in.readFully(buf);
             _data = buf;
         }
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java 
b/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
index 712693554c..2a93a11d52 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
@@ -23,10 +23,10 @@ import java.util.Arrays;
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.poi.util.ArrayUtil;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
@@ -83,7 +83,8 @@ public final class WriteAccessRecord extends StandardRecord {
             if (in.isEncrypted()) {
                 // WPS Office seems to generate files with this record 
unencrypted (#66115)
                 // Libre Office/Excel can read those, but Excel will convert 
those back to encrypted
-                data = IOUtils.safelyAllocate(in.remaining(), STRING_SIZE);
+                ArrayUtil.strictAllocateCheck(in.remaining(), STRING_SIZE);
+                data = new byte[in.remaining()];
                 in.readPlain(data, 0, data.length);
                 int i = data.length;
                 // PAD_CHAR is filled for every byte even for UTF16 strings
@@ -97,7 +98,8 @@ public final class WriteAccessRecord extends StandardRecord {
                 // String header looks wrong (probably missing)
                 // OOO doc says this is optional anyway.
                 byteCnt = 3 + in.remaining();
-                data = IOUtils.safelyAllocate(byteCnt, DATA_SIZE);
+                ArrayUtil.strictAllocateCheck(byteCnt, DATA_SIZE);
+                data = new byte[byteCnt];
                 LittleEndian.putUShort(data, 0, nChars);
                 LittleEndian.putByte(data, 2, is16BitFlag);
                 in.readFully(data, 3, byteCnt-3);
@@ -105,7 +107,8 @@ public final class WriteAccessRecord extends StandardRecord 
{
             }
         } else {
             // the normal case ...
-            data = IOUtils.safelyAllocate(in.remaining(), STRING_SIZE);
+            ArrayUtil.strictAllocateCheck(in.remaining(), STRING_SIZE);
+            data = new byte[in.remaining()];
             in.readFully(data);
             if (UTF16FLAG.isSet(is16BitFlag)) {
                 // the spec only allows up to 109 bytes for the string in this 
record, but it seems some broken
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
 
b/poi/src/main/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
index 44763597cb..ab72bdfe89 100644
--- 
a/poi/src/main/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
+++ 
b/poi/src/main/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
@@ -31,7 +31,7 @@ import org.apache.poi.hssf.record.TableRecord;
 import org.apache.poi.ss.formula.ptg.ExpPtg;
 import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.ArrayUtil;
 
 /**
  * Manages various auxiliary records while constructing a
@@ -43,7 +43,16 @@ import org.apache.poi.util.IOUtils;
  * </ul>
  */
 public final class SharedValueManager {
-    private static final int MAX_NUMBER_AGGS = 10_000;
+    private static final int DEFAULT_MAX_NUMBER_AGGS = 10_000;
+    private static int MAX_NUMBER_AGGS = DEFAULT_MAX_NUMBER_AGGS;
+
+    public static void setMaxNumberOfFormulaRecordAggregates(int 
maxNumberOfFormulaRecordAggregates) {
+        MAX_NUMBER_AGGS = maxNumberOfFormulaRecordAggregates;
+    }
+
+    public static int getMaxNumberOfFormulaRecordAggregates() {
+        return MAX_NUMBER_AGGS;
+    }
 
     private static final class SharedFormulaGroup {
         private final SharedFormulaRecord _sfr;
@@ -68,7 +77,8 @@ public final class SharedValueManager {
 
             // ensure we do not try to initialize a very large amount of 
formula-record-aggregates
             int allocateSize = width * height;
-            IOUtils.safelyAllocateCheck(allocateSize, MAX_NUMBER_AGGS);
+            ArrayUtil.safelyAllocateCheck(allocateSize, MAX_NUMBER_AGGS,
+                    
"SharedValueManager.setMaxNumberOfFormulaRecordAggregates");
 
             _frAggs = new FormulaRecordAggregate[allocateSize];
             _numberOfFormulas = 0;
diff --git a/poi/src/main/java/org/apache/poi/hssf/record/common/ExtRst.java 
b/poi/src/main/java/org/apache/poi/hssf/record/common/ExtRst.java
index d798b0cc39..9e6c13ac0a 100644
--- a/poi/src/main/java/org/apache/poi/hssf/record/common/ExtRst.java
+++ b/poi/src/main/java/org/apache/poi/hssf/record/common/ExtRst.java
@@ -28,7 +28,6 @@ import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.GenericRecordUtil;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.StringUtil;
@@ -125,7 +124,7 @@ public class ExtRst implements Comparable<ExtRst>, 
GenericRecord {
             LOG.atWarn().log("ExtRst overran by {} bytes", 
box(-extraDataLength));
             extraDataLength = 0;
         }
-        extraData = IOUtils.safelyAllocate(extraDataLength, 
HSSFWorkbook.getMaxRecordLength());
+        extraData = HSSFWorkbook.safelyAllocate(extraDataLength);
         for(int i=0; i<extraData.length; i++) {
             extraData[i] = in.readByte();
         }
diff --git 
a/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
 
b/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
index 63ed8e1fad..112d02c0e9 100644
--- 
a/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
+++ 
b/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
@@ -25,7 +25,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.poifs.crypt.ChunkedCipherInputStream;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
@@ -44,7 +43,7 @@ public final class Biff8DecryptingStream implements 
BiffHeaderInput, LittleEndia
 
     public Biff8DecryptingStream(InputStream in, int initialOffset, 
EncryptionInfo info) throws RecordFormatException {
         try {
-            byte[] initialBuf = IOUtils.safelyAllocate(initialOffset, 
HSSFWorkbook.getMaxRecordLength());
+            byte[] initialBuf = HSSFWorkbook.safelyAllocate(initialOffset);
             InputStream stream;
             if (initialOffset == 0) {
                 stream = in;
diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java 
b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 9862b38d5d..50a9efc74f 100644
--- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -244,6 +244,10 @@ public final class HSSFWorkbook extends POIDocument 
implements Workbook {
         return ioMaxSize < 0 ? MAX_IMAGE_LENGTH : Math.min(MAX_IMAGE_LENGTH, 
ioMaxSize);
     }
 
+    public static byte[] safelyAllocate(long len) {
+        return IOUtils.safelyAllocate(len, MAX_RECORD_LENGTH, 
"HSSFWorkbook.setMaxRecordLength()");
+    }
+
     /**
      * Creates new HSSFWorkbook from scratch (start here!)
      */
@@ -1670,7 +1674,7 @@ public final class HSSFWorkbook extends POIDocument 
implements Workbook {
                 if (sid == BoundSheetRecord.sid) {
                     // special case for the field_1_position_of_BOF 
(=lbPlyPos) field of
                     // the BoundSheet8 record which must be unencrypted
-                    byte[] bsrBuf = IOUtils.safelyAllocate(len, 
MAX_RECORD_LENGTH);
+                    byte[] bsrBuf = safelyAllocate(len);
                     plain.readFully(bsrBuf);
                     os.writePlain(bsrBuf, 0, 4);
                     os.write(bsrBuf, 4, len - 4);
@@ -2078,7 +2082,8 @@ public final class HSSFWorkbook extends POIDocument 
implements Workbook {
             case PICTURE_TYPE_WMF:
                 // remove first 22 bytes if file starts with the WMF placeable 
header
                 if (FileMagic.valueOf(pictureData) == FileMagic.WMF) {
-                    pictureData = IOUtils.safelyClone(pictureData, 22, 
pictureData.length - 22, getMaxImageLength());
+                    pictureData = IOUtils.safelyClone(pictureData, 22, 
pictureData.length - 22,
+                            getMaxImageLength(), 
"HSSFWorkbook.setMaxImageLength()");
                 }
                 // fall through
             case PICTURE_TYPE_EMF:
diff --git a/poi/src/main/java/org/apache/poi/util/ArrayUtil.java 
b/poi/src/main/java/org/apache/poi/util/ArrayUtil.java
index 504b80e625..ce86100d88 100644
--- a/poi/src/main/java/org/apache/poi/util/ArrayUtil.java
+++ b/poi/src/main/java/org/apache/poi/util/ArrayUtil.java
@@ -17,7 +17,6 @@
 
 package org.apache.poi.util;
 
-
 import java.util.Arrays;
 
 /**
@@ -96,15 +95,18 @@ public final class ArrayUtil {
      * @throws RecordFormatException if the length is negative or too long
      */
     public static void safelyAllocateCheck(long length, int maxLength, String 
limitMethod) {
-        if (length < 0L) {
-            throw new RecordFormatException("Can't allocate an array of length 
< 0, but had " + length + " and " + maxLength);
-        }
-        if (length > (long)Integer.MAX_VALUE) {
-            throw new RecordFormatException("Can't allocate an array > " + 
Integer.MAX_VALUE);
-        }
+        IOUtils.globalLengthChecks(length);
         if (length > maxLength) {
             IOUtils.throwRFE(length, maxLength, limitMethod);
         }
     }
 
+    public static void strictAllocateCheck(long length, int maxLength) {
+        IOUtils.globalLengthChecks(length);
+        if (length > maxLength) {
+            IOUtils.throwStrictLimitRFE(length, maxLength);
+        }
+    }
+
+
 }
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 bc36232251..733bcb1c56 100644
--- a/poi/src/main/java/org/apache/poi/util/IOUtils.java
+++ b/poi/src/main/java/org/apache/poi/util/IOUtils.java
@@ -232,9 +232,7 @@ public final class IOUtils {
      * @since 5.4.1
      */
     public static byte[] toByteArray(InputStream stream, final long length, 
final int maxLength) throws IOException {
-        if (length > Integer.MAX_VALUE) {
-            throwRFE(length, maxLength);
-        }
+        globalLengthChecks(length);
         return toByteArray(stream, Math.toIntExact(length),
                 maxLength, true, length != Integer.MAX_VALUE);
     }
@@ -613,12 +611,7 @@ public final class IOUtils {
      * @throws RecordFormatException if the length is negative or too long
      */
     public static void safelyAllocateCheck(long length, int maxLength) {
-        if (length < 0L) {
-            throw new RecordFormatException("Can't allocate an array of length 
< 0, but had " + length + " and " + maxLength);
-        }
-        if (length > (long)Integer.MAX_VALUE) {
-            throw new RecordFormatException("Can't allocate an array > " + 
Integer.MAX_VALUE);
-        }
+        globalLengthChecks(length);
         checkLength(length, maxLength);
     }
 
@@ -634,27 +627,36 @@ public final class IOUtils {
      * @throws RecordFormatException if the length is negative or too long
      */
     public static void safelyAllocateCheck(long length, int maxLength, String 
limitMethod) {
-        if (length < 0L) {
-            throw new RecordFormatException("Can't allocate an array of length 
< 0, but had " + length + " and " + maxLength);
-        }
-        if (length > (long)Integer.MAX_VALUE) {
-            throw new RecordFormatException("Can't allocate an array > " + 
Integer.MAX_VALUE);
-        }
+        globalLengthChecks(length);
         checkLength(length, maxLength, limitMethod);
     }
 
     public static byte[] safelyClone(byte[] src, int offset, int length, int 
maxLength) {
+        return safelyClone(src, offset, length, maxLength, null);
+    }
+
+    public static byte[] safelyClone(byte[] src, int offset, int length,
+                                     int maxLength, String limitMethod) {
         if (src == null) {
             return null;
         }
 
         if (offset < 0 || length < 0 || maxLength < 0) {
-            throw new RecordFormatException("Invalid offset/length specified: "
-                    + "offset: " + offset + ", length: " + length + ", 
maxLength: " + maxLength);
+            if (limitMethod == null) {
+                throw new RecordFormatException(String.format(Locale.ROOT, 
"Invalid offset/length specified: " +
+                        "offset: %d, length: %d, maxLength: %d", offset, 
length, maxLength));
+            }
+            throw new RecordFormatException(String.format(Locale.ROOT, 
"Invalid offset/length specified: " +
+                    "offset: %d, length: %d, maxLength: %d.%n" +
+                    "You can set a higher override value with %s.", offset, 
length, maxLength, limitMethod));
         }
 
         int realLength = Math.min(src.length - offset, length);
-        safelyAllocateCheck(realLength, maxLength);
+        if (limitMethod == null) {
+            safelyAllocateCheck(realLength, maxLength);
+        } else {
+            safelyAllocateCheck(realLength, maxLength, limitMethod);
+        }
         return Arrays.copyOfRange(src, offset, offset+realLength);
     }
 
@@ -705,7 +707,15 @@ public final class IOUtils {
                 ", but the maximum length for this record type is %,d.%n" +
                 "If the file is not corrupt and not large, please open an 
issue on bugzilla to request %n" +
                 "increasing the maximum allowable size for this record 
type.%n" +
-                "You can set a higher override value with %s", length, 
maxLength, limitMethod));
+                "You can set a higher override value with %s.", length, 
maxLength, limitMethod));
+    }
+
+    // no override available for the limit
+    static void throwStrictLimitRFE(long length, int maxLength) {
+        throw new RecordFormatException(String.format(Locale.ROOT, "Tried to 
allocate an array of length %,d" +
+                ", but the maximum length for this record type is %,d.%n" +
+                "If the file is not corrupt and not large, please open an 
issue on bugzilla to request %n" +
+                "increasing the maximum allowable size for this record 
type.%n", length, maxLength));
     }
 
     private static void throwRecordTruncationException(final int maxLength) {
@@ -713,6 +723,19 @@ public final class IOUtils {
                 "for this record type is %,d.%n" +
                 "If the file is not corrupt and not large, please open an 
issue on bugzilla to request %n" +
                 "increasing the maximum allowable size for this record 
type.%n" +
-                "You can set a higher override value with 
IOUtils.setByteArrayMaxOverride()", maxLength));
+                "You can set a higher override value with 
IOUtils.setByteArrayMaxOverride().", maxLength));
+    }
+
+    static void globalLengthChecks(long length) {
+        if (length < 0L) {
+            throw new RecordFormatException(String.format(Locale.ROOT,
+                    "Tried to allocate an array with negative length; %d was 
requested.",
+                    length));
+        }
+        if (length > (long)Integer.MAX_VALUE) {
+            throw new RecordFormatException(String.format(Locale.ROOT,
+                    "Tried to allocate an array with length greater than max 
allowed int (%d); %d was requested.",
+                    Integer.MAX_VALUE, length));
+        }
     }
 }
diff --git a/test-data/poi-integration-exceptions.csv 
b/test-data/poi-integration-exceptions.csv
index f38fec98ff..d70a72058d 100644
--- a/test-data/poi-integration-exceptions.csv
+++ b/test-data/poi-integration-exceptions.csv
@@ -187,8 +187,8 @@ 
slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-6710128412590080.ppt,"han
 
slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-6710128412590080.ppt,extract,HPSF,,java.lang.IllegalArgumentException,Had
 unexpected type of entry for name,
 
slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-6710128412590080.ppt,additional,HPSF,,java.lang.IllegalStateException,Buffer
 overrun,
 
slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-6710128412590080.ppt,handle,HPSF,,org.opentest4j.AssertionFailedError,expected:
 <true> but was: <false>,
-diagram/clusterfuzz-testcase-minimized-POIHDGFFuzzer-5947849161179136.vsd,extract,"HDGF,HPSF",,org.apache.poi.util.RecordFormatException,Can't
 allocate an array > 2147483647,
-diagram/clusterfuzz-testcase-minimized-POIHDGFFuzzer-5947849161179136.vsd,handle,HDGF,,org.apache.poi.util.RecordFormatException,Can't
 allocate an array > 2147483647,
+diagram/clusterfuzz-testcase-minimized-POIHDGFFuzzer-5947849161179136.vsd,extract,"HDGF,HPSF",,org.apache.poi.util.RecordFormatException,Tried
 to allocate an array with length greater than max allowed int (2147483647); 
2450525952 was requested.,
+diagram/clusterfuzz-testcase-minimized-POIHDGFFuzzer-5947849161179136.vsd,handle,HDGF,,org.apache.poi.util.RecordFormatException,Tried
 to allocate an array with length greater than max allowed int (2147483647); 
2450525952 was requested.,
 
diagram/clusterfuzz-testcase-minimized-POIHDGFFuzzer-5947849161179136.vsd,"handle,additional",HPSF,,java.util.NoSuchElementException,Can't
 read past the end of the stream,
 
hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4735011465854976.msg,extract,"HSMF,HPSF",,java.lang.IllegalArgumentException,ChunkId
 and type of chunk did not match,
 
hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4735011465854976.msg,handle,HSMF,,java.lang.IllegalArgumentException,ChunkId
 and type of chunk did not match,
@@ -404,5 +404,5 @@ 
slideshow/clusterfuzz-testcase-minimized-POIXSLFFuzzer-6435650376957952.pptx,han
 
slideshow/clusterfuzz-testcase-minimized-POIXSLFFuzzer-6435650376957952.pptx,extract,"XSLF,OPC",,java.lang.IllegalStateException,org.apache.poi.ooxml.POIXMLException,
 
slideshow/clusterfuzz-testcase-minimized-POIFileHandlerFuzzer-6466833057382400.emf,"handle,extract",HEMF,,org.apache.poi.util.RecordFormatException,java.lang.IllegalStateException:
 Unexpected end-of-file,
 
slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-4983252485210112.ppt,"handle,additional",HPSF,,java.lang.IndexOutOfBoundsException,Block
 21 not found,
-slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-4983252485210112.ppt,handle,HSLF,,org.apache.poi.util.RecordFormatException,"Can't
 allocate an array of length < 0, but had -1579150891 and 1000000",
+slideshow/clusterfuzz-testcase-minimized-POIHSLFFuzzer-4983252485210112.ppt,handle,HSLF,,org.apache.poi.util.RecordFormatException,Tried
 to allocate an array with negative length; -1579150891 was requested.,
 
slideshow/clusterfuzz-testcase-minimized-POIFileHandlerFuzzer-6060921738035200.wmf,handle,HWMF,,java.lang.IllegalStateException,invalid
 wmf file
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to