From c6f2c7fa612f1dc8a11c2594a87c517716a6000d Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 Jun 2026 20:26:35 +0100 Subject: [PATCH 1/4] more int overflow risks --- .../poi/xslf/usermodel/XSLFPictureShape.java | 5 ++++- .../apache/poi/xssf/model/ExternalLinksTable.java | 2 +- .../java/org/apache/poi/xssf/model/MapInfo.java | 4 ++-- .../org/apache/poi/xssf/streaming/SXSSFSheet.java | 3 ++- .../apache/poi/xssf/usermodel/XSSFCellStyle.java | 9 +++++---- .../apache/poi/xwpf/usermodel/XWPFParagraph.java | 15 +++++++++------ .../org/apache/poi/xwpf/usermodel/XWPFRun.java | 2 +- .../org/apache/poi/hdgf/chunks/ChunkHeader.java | 6 +++--- .../apache/poi/hemf/draw/HemfImageRenderer.java | 6 +++++- .../apache/poi/hemf/record/emf/HemfComment.java | 4 ++-- .../apache/poi/hemf/record/emf/HemfHeader.java | 6 +++--- .../poi/hemf/record/emf/HemfRecordIterator.java | 2 +- .../org/apache/poi/hpbf/model/QuillContents.java | 4 ++-- .../java/org/apache/poi/hslf/blip/Bitmap.java | 5 +++-- .../java/org/apache/poi/hslf/dev/PPTXMLDump.java | 2 +- .../poi/hslf/dev/SlideShowRecordDumper.java | 2 +- .../poi/hslf/dev/UserEditAndPersistListing.java | 2 +- .../org/apache/poi/hslf/record/SlideAtom.java | 2 +- 18 files changed, 47 insertions(+), 34 deletions(-) diff --git a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java index aec5faccf69..b429a22ad2f 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java @@ -45,6 +45,7 @@ import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.Placeholder; import org.apache.poi.util.Beta; +import org.apache.poi.util.MathUtil; import org.apache.poi.util.Units; import org.apache.poi.xslf.draw.SVGImageRenderer; import org.apache.xmlbeans.XmlCursor; @@ -372,7 +373,9 @@ public static XSLFPictureShape addSvgImage(XSLFSheet sheet, XSLFPictureData svgP Dimension2D dim = renderer.getDimension(); Rectangle2D anc = (anchor != null) ? anchor - : new Rectangle2D.Double(0,0, Units.pixelToPoints((int)dim.getWidth()), Units.pixelToPoints((int)dim.getHeight())); + : new Rectangle2D.Double(0,0, + Units.pixelToPoints(MathUtil.safeDoubleToInt(dim.getWidth())), + Units.pixelToPoints(MathUtil.safeDoubleToInt(dim.getHeight()))); PictureType pt = (previewType != null) ? previewType : PictureType.PNG; if (pt != PictureType.JPEG && pt != PictureType.GIF && pt != PictureType.PNG) { diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/model/ExternalLinksTable.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/model/ExternalLinksTable.java index 89b2b87e29f..37bc7f28728 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/model/ExternalLinksTable.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/model/ExternalLinksTable.java @@ -257,7 +257,7 @@ public String getSheetName() { @Override public int getSheetIndex() { if (name.isSetSheetId()) { - return (int)name.getSheetId(); + return Math.toIntExact(name.getSheetId()); } return -1; } diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/model/MapInfo.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/model/MapInfo.java index 46eee39c366..20bde4c85a1 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/model/MapInfo.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/model/MapInfo.java @@ -75,7 +75,7 @@ public void readFrom(InputStream is) throws IOException { maps= new HashMap<>(); for(CTMap map :mapInfo.getMapArray()){ - maps.put((int)map.getID(), new XSSFMap(map,this)); + maps.put(Math.toIntExact(map.getID()), new XSSFMap(map,this)); } } catch (XmlException e) { @@ -127,7 +127,7 @@ public XSSFMap getXSSFMapByName(String name){ XSSFMap matchedMap = null; - for(XSSFMap map :maps.values()){ + for(XSSFMap map : maps.values()){ if(map.getCtMap().getName()!=null && map.getCtMap().getName().equals(name)){ matchedMap = map; } diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index 9ac5399f45d..b86f9350255 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -30,6 +30,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.ss.util.PaneInformation; import org.apache.poi.ss.util.SheetUtil; import org.apache.poi.util.Internal; +import org.apache.poi.util.MathUtil; import org.apache.poi.util.NotImplemented; import org.apache.poi.util.Removal; import org.apache.poi.xssf.usermodel.*; @@ -1667,7 +1668,7 @@ public void autoSizeColumn(int column, boolean useMergedCells) { // get the best-fit width of rows currently in the random access window final double w1 = SheetUtil.getColumnWidth(this, column, useMergedCells); - final int activeWidth = (int) ((256 * w1) + getArbitraryExtraWidth()); + final int activeWidth = MathUtil.safeDoubleToInt((256 * w1) + getArbitraryExtraWidth()); // the best-fit width for both flushed rows and random access window rows // flushedWidth or activeWidth may be negative if column contains only blank cells diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java index 92615891524..5a0ddfbbc37 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java @@ -34,6 +34,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.util.CellUtil; import org.apache.poi.util.Internal; +import org.apache.poi.util.MathUtil; import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.ThemesTable; import org.apache.poi.xssf.usermodel.extensions.XSSFCellAlignment; @@ -369,7 +370,7 @@ public XSSFColor getFillBackgroundXSSFColor() { // bug 56295: handle missing applyFill attribute as "true" because Excel does as well if(_cellXf.isSetApplyFill() && !_cellXf.getApplyFill()) return null; - int fillIndex = (int)_cellXf.getFillId(); + int fillIndex = Math.toIntExact(_cellXf.getFillId()); XSSFCellFill fg = _stylesSource.getFillAt(fillIndex); XSSFColor fillBackgroundColor = fg.getFillBackgroundColor(); @@ -408,7 +409,7 @@ public XSSFColor getFillForegroundXSSFColor() { // bug 56295: handle missing applyFill attribute as "true" because Excel does as well if(_cellXf.isSetApplyFill() && !_cellXf.getApplyFill()) return null; - int fillIndex = (int)_cellXf.getFillId(); + int fillIndex = Math.toIntExact(_cellXf.getFillId()); XSSFCellFill fg = _stylesSource.getFillAt(fillIndex); XSSFColor fillForegroundColor = fg.getFillForegroundColor(); @@ -423,7 +424,7 @@ public FillPatternType getFillPattern() { // bug 56295: handle missing applyFill attribute as "true" because Excel does as well if(_cellXf.isSetApplyFill() && !_cellXf.getApplyFill()) return FillPatternType.NO_FILL; - int fillIndex = (int)_cellXf.getFillId(); + int fillIndex = MathUtil.safeDoubleToInt(_cellXf.getFillId()); XSSFCellFill fill = _stylesSource.getFillAt(fillIndex); STPatternType.Enum ptrn = fill.getPatternType(); @@ -935,7 +936,7 @@ private CTFill getCTFill(){ CTFill ct; // bug 56295: handle missing applyFill attribute as "true" because Excel does as well if(!_cellXf.isSetApplyFill() || _cellXf.getApplyFill()) { - int fillIndex = (int)_cellXf.getFillId(); + int fillIndex = MathUtil.safeDoubleToInt(_cellXf.getFillId()); XSSFCellFill cf = _stylesSource.getFillAt(fillIndex); ct = (CTFill)cf.getCTFill().copy(); diff --git a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java index 680fe2433de..62c81e1e81c 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java @@ -25,6 +25,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ooxml.util.POIXMLUnits; import org.apache.poi.util.Internal; +import org.apache.poi.util.MathUtil; import org.apache.poi.util.Units; import org.apache.poi.wp.usermodel.Paragraph; import org.apache.xmlbeans.XmlCursor; @@ -932,7 +933,8 @@ public void setPageBreak(boolean pageBreak) { */ public int getSpacingAfter() { CTSpacing spacing = getCTSpacing(false); - return (spacing != null && spacing.isSetAfter()) ? (int)Units.toDXA(POIXMLUnits.parseLength(spacing.xgetAfter())) : -1; + return (spacing != null && spacing.isSetAfter()) ? + MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(spacing.xgetAfter()))) : -1; } /** @@ -998,7 +1000,8 @@ public void setSpacingAfterLines(int spaces) { */ public int getSpacingBefore() { CTSpacing spacing = getCTSpacing(false); - return (spacing != null && spacing.isSetBefore()) ? (int)Units.toDXA(POIXMLUnits.parseLength(spacing.xgetBefore())) : -1; + return (spacing != null && spacing.isSetBefore()) ? + MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(spacing.xgetBefore()))) : -1; } /** @@ -1146,7 +1149,7 @@ public void setSpacingBetween(double spacing) { public int getIndentationLeft() { CTInd indentation = getCTInd(false); return (indentation != null && indentation.isSetLeft()) - ? (int)Units.toDXA(POIXMLUnits.parseLength(indentation.xgetLeft())) + ? MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(indentation.xgetLeft()))) : -1; } @@ -1212,7 +1215,7 @@ public void setIndentationLeftChars(int indentation) { public int getIndentationRight() { CTInd indentation = getCTInd(false); return (indentation != null && indentation.isSetRight()) - ? (int)Units.toDXA(POIXMLUnits.parseLength(indentation.xgetRight())) + ? MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(indentation.xgetRight()))) : -1; } @@ -1277,7 +1280,7 @@ public void setIndentationRightChars(int indentation) { public int getIndentationHanging() { CTInd indentation = getCTInd(false); return (indentation != null && indentation.isSetHanging()) - ? (int)Units.toDXA(POIXMLUnits.parseLength(indentation.xgetHanging())) : -1; + ? MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(indentation.xgetHanging()))) : -1; } /** @@ -1318,7 +1321,7 @@ public void setIndentationHanging(int indentation) { public int getIndentationFirstLine() { CTInd indentation = getCTInd(false); return (indentation != null && indentation.isSetFirstLine()) - ? (int)Units.toDXA(POIXMLUnits.parseLength(indentation.xgetFirstLine())) + ? MathUtil.safeDoubleToInt(Units.toDXA(POIXMLUnits.parseLength(indentation.xgetFirstLine()))) : -1; } diff --git a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFRun.java b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFRun.java index 687c5181626..9fc06c8c004 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFRun.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFRun.java @@ -807,7 +807,7 @@ public int getKerning() { if (pr == null || pr.sizeOfKernArray() == 0) { return 0; } - return (int)POIXMLUnits.parseLength(pr.getKernArray(0).xgetVal()); + return Math.toIntExact(POIXMLUnits.parseLength(pr.getKernArray(0).xgetVal())); } @Override diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java b/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java index 209550a7864..f0f37feca78 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java @@ -47,9 +47,9 @@ public static ChunkHeader createChunkHeader(int documentVersion, byte[] data, in } else { ch = new ChunkHeaderV6(); } - ch.setType((int) LittleEndian.getUInt(data, offset)); - ch.setId((int) LittleEndian.getUInt(data, offset + 4)); - ch.setUnknown1((int) LittleEndian.getUInt(data, offset + 8)); + ch.setType(Math.toIntExact(LittleEndian.getUInt(data, offset))); + ch.setId(Math.toIntExact(LittleEndian.getUInt(data, offset + 4))); + ch.setUnknown1(Math.toIntExact(LittleEndian.getUInt(data, offset + 8))); // Match the v4/v5 branch below: reject lengths that would silently // truncate when narrowing the uint32 to a signed int, rather than // letting a wrapped value flow into the offset arithmetic in diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/draw/HemfImageRenderer.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/draw/HemfImageRenderer.java index 27efbe18a93..cf348154f03 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/draw/HemfImageRenderer.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/draw/HemfImageRenderer.java @@ -39,6 +39,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.sl.draw.EmbeddedExtractor; import org.apache.poi.sl.draw.ImageRenderer; import org.apache.poi.sl.usermodel.PictureData; +import org.apache.poi.util.MathUtil; import org.apache.poi.util.Units; @SuppressWarnings("unused") @@ -84,7 +85,10 @@ public BufferedImage getImage(Dimension2D dim) { return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); } - BufferedImage bufImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB); + BufferedImage bufImg = new BufferedImage( + MathUtil.safeDoubleToInt(dim.getWidth()), + MathUtil.safeDoubleToInt(dim.getHeight()), + BufferedImage.TYPE_INT_ARGB); Graphics2D g = bufImg.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java index ff9d0f48a98..3ca019ef5e1 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java @@ -153,9 +153,9 @@ public Map> getGenericProperties() { static void validateCommentType(final LittleEndianInputStream leis, HemfCommentRecordType commentType) { // comment identifiers are uint32 values used as bit-pattern identifiers, not numeric values - int commentIdentifier = (int) leis.readUInt(); + int commentIdentifier = Math.toIntExact(leis.readUInt()); if (commentIdentifier == HemfCommentRecordType.emfPublic.id) { - commentIdentifier = (int) leis.readUInt(); + commentIdentifier = Math.toIntExact(leis.readUInt()); } assert(commentIdentifier == commentType.id); } 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 01b43d613f2..f9f8943e8d9 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 @@ -167,7 +167,7 @@ public long init(LittleEndianInputStream leis, long recordSize, long recordId) t size += readDimensionInt(leis, milliDimension); if (nDescription > 0 && offDescription > 0) { - long skip = offDescription - (size + HEADER_SIZE); + int skip = Math.toIntExact(offDescription - (size + HEADER_SIZE)); long descriptionBytes = (nDescription - 1) * LittleEndianConsts.SHORT_SIZE; long descriptionEnd = offDescription + nDescription * LittleEndianConsts.SHORT_SIZE; if (skip < 0 || descriptionEnd > recordSize + HEADER_SIZE || skip + descriptionBytes > Integer.MAX_VALUE) { @@ -175,8 +175,8 @@ public long init(LittleEndianInputStream leis, long recordSize, long recordId) t } int maxDescriptionLength = Math.toIntExact(Math.min(recordSize, Integer.MAX_VALUE)); IOUtils.safelyAllocateCheck(descriptionBytes, maxDescriptionLength); - leis.mark((int)(skip + descriptionBytes)); - leis.skipFully((int)skip); + leis.mark(Math.toIntExact(skip + descriptionBytes)); + leis.skipFully(skip); byte[] buf = IOUtils.safelyAllocate(descriptionBytes, maxDescriptionLength); leis.readFully(buf); description = new String(buf, StandardCharsets.UTF_16LE).replace((char)0, ' ').trim(); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java index 64b4d176ef1..69330553906 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java @@ -81,7 +81,7 @@ private HemfRecord _next() { if (readBytes > remBytes) { throw new RecordFormatException("Record limit exceeded - readBytes: "+readBytes+" / remBytes: "+remBytes); } - stream.skipFully((int) (remBytes - readBytes)); + stream.skipFully(Math.toIntExact(remBytes - readBytes)); } catch (RecordFormatException e) { throw e; } catch (IOException|RuntimeException e) { diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hpbf/model/QuillContents.java b/poi-scratchpad/src/main/java/org/apache/poi/hpbf/model/QuillContents.java index fdc1bd30103..ee7aac0aee0 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hpbf/model/QuillContents.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hpbf/model/QuillContents.java @@ -79,8 +79,8 @@ public QuillContents(DirectoryNode baseDir) throws IOException { "QuillContents bit offset " + fromU + " exceeds Integer.MAX_VALUE"); } IOUtils.safelyAllocateCheck(lenU, EscherPart.getMaxRecordLength()); - int from = (int)fromU; - int len = (int)lenU; + int from = Math.toIntExact(fromU); + int len = Math.toIntExact(lenU); byte[] bitData = IOUtils.safelyClone(data, from, len, EscherPart.getMaxRecordLength()); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/blip/Bitmap.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/blip/Bitmap.java index 6e489c7012a..e143e5e0406 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/blip/Bitmap.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/blip/Bitmap.java @@ -31,6 +31,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.hslf.usermodel.HSLFPictureData; import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; +import org.apache.poi.util.MathUtil; import org.apache.poi.util.Units; /** @@ -98,8 +99,8 @@ public Dimension getImageDimension() { try (InputStream is = UnsynchronizedByteArrayInputStream.builder().setByteArray(getData()).get()){ BufferedImage bi = ImageIO.read(is); return new Dimension( - (int)Units.pixelToPoints(bi.getWidth()), - (int)Units.pixelToPoints(bi.getHeight()) + MathUtil.safeDoubleToInt(Units.pixelToPoints(bi.getWidth())), + MathUtil.safeDoubleToInt(Units.pixelToPoints(bi.getHeight())) ); } catch (IOException e) { return new Dimension(200,200); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java index 96e3292b66c..7cc5ebb9c7e 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java @@ -121,7 +121,7 @@ public void dump(byte[] data, int offset, int length, int padding) throws IOExce pos += LittleEndianConsts.SHORT_SIZE; int type = LittleEndian.getUShort(data, pos); pos += LittleEndianConsts.SHORT_SIZE; - int size = (int)LittleEndian.getUInt(data, pos); + int size = Math.toIntExact(LittleEndian.getUInt(data, pos)); pos += LittleEndianConsts.INT_SIZE; if (size < 0) { diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowRecordDumper.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowRecordDumper.java index 30242ba0817..18d9494475a 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowRecordDumper.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/SlideShowRecordDumper.java @@ -235,7 +235,7 @@ public void walkTree(int depth, int pos, Record[] records, int indent) throws IO int len = getDiskLen(r); // Grab the type as hex - String hexType = makeHex((int) r.getRecordType(), 4); + String hexType = makeHex(Math.toIntExact(r.getRecordType()), 4); String rHexType = reverseHex(hexType); // Grab the hslf.record type diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java index f0aeaff1267..de9345cdca4 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java @@ -122,6 +122,6 @@ public static org.apache.poi.hslf.record.Record findRecordAtPos(int pos) { long type = LittleEndian.getUShort(fileContents, pos+2); long rlen = LittleEndian.getUInt(fileContents, pos+4); - return Record.createRecordForType(type,fileContents,pos,(int)rlen+8); + return Record.createRecordForType(type,fileContents,pos,Math.toIntExact(rlen+8)); } } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/record/SlideAtom.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/record/SlideAtom.java index 42fa25e1c9e..72b612d384e 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/record/SlideAtom.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/record/SlideAtom.java @@ -109,7 +109,7 @@ protected SlideAtom(byte[] source, int start, int len) { public SlideAtom(){ _header = new byte[8]; LittleEndian.putUShort(_header, 0, 2); - LittleEndian.putUShort(_header, 2, (int)_type); + LittleEndian.putUShort(_header, 2, Math.toIntExact(_type)); LittleEndian.putInt(_header, 4, 24); byte[] ssdate = new byte[12]; From 91ef29bb1c18fbbb5818c55ff7a160014aad7d61 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 Jun 2026 21:38:56 +0100 Subject: [PATCH 2/4] some reverts due to test issues --- .../java/org/apache/poi/hdgf/chunks/ChunkHeader.java | 6 +++--- .../org/apache/poi/hemf/record/emf/HemfComment.java | 4 ++-- .../main/java/org/apache/poi/hslf/dev/PPTXMLDump.java | 10 +++++----- .../apache/poi/hslf/dev/UserEditAndPersistListing.java | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java b/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java index f0f37feca78..209550a7864 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hdgf/chunks/ChunkHeader.java @@ -47,9 +47,9 @@ public static ChunkHeader createChunkHeader(int documentVersion, byte[] data, in } else { ch = new ChunkHeaderV6(); } - ch.setType(Math.toIntExact(LittleEndian.getUInt(data, offset))); - ch.setId(Math.toIntExact(LittleEndian.getUInt(data, offset + 4))); - ch.setUnknown1(Math.toIntExact(LittleEndian.getUInt(data, offset + 8))); + ch.setType((int) LittleEndian.getUInt(data, offset)); + ch.setId((int) LittleEndian.getUInt(data, offset + 4)); + ch.setUnknown1((int) LittleEndian.getUInt(data, offset + 8)); // Match the v4/v5 branch below: reject lengths that would silently // truncate when narrowing the uint32 to a signed int, rather than // letting a wrapped value flow into the offset arithmetic in diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java index 3ca019ef5e1..ff9d0f48a98 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java @@ -153,9 +153,9 @@ public Map> getGenericProperties() { static void validateCommentType(final LittleEndianInputStream leis, HemfCommentRecordType commentType) { // comment identifiers are uint32 values used as bit-pattern identifiers, not numeric values - int commentIdentifier = Math.toIntExact(leis.readUInt()); + int commentIdentifier = (int) leis.readUInt(); if (commentIdentifier == HemfCommentRecordType.emfPublic.id) { - commentIdentifier = Math.toIntExact(leis.readUInt()); + commentIdentifier = (int) leis.readUInt(); } assert(commentIdentifier == commentType.id); } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java index 7cc5ebb9c7e..784a815b70b 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/PPTXMLDump.java @@ -121,10 +121,10 @@ public void dump(byte[] data, int offset, int length, int padding) throws IOExce pos += LittleEndianConsts.SHORT_SIZE; int type = LittleEndian.getUShort(data, pos); pos += LittleEndianConsts.SHORT_SIZE; - int size = Math.toIntExact(LittleEndian.getUInt(data, pos)); + long size = LittleEndian.getUInt(data, pos); pos += LittleEndianConsts.INT_SIZE; - if (size < 0) { + if (size < 0 || size > Integer.MAX_VALUE) { // stop processing of invalid header data continue; } @@ -143,15 +143,15 @@ public void dump(byte[] data, int offset, int length, int padding) throws IOExce boolean isContainer = (info & 0x000F) == 0x000F; if (isContainer) { //continue to dump child records - dump(data, pos, size, padding); + dump(data, pos, Math.toIntExact(size), padding); } else { //dump first 100 bytes of the atom data - dump(out, data, pos, Math.min(size, data.length-pos), padding, true); + dump(out, data, pos, Math.toIntExact(Math.min(size, data.length-pos)), padding, true); } padding--; write(out, "" + CR, padding); - pos += size; + pos += Math.toIntExact(size); } } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java index de9345cdca4..f0aeaff1267 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hslf/dev/UserEditAndPersistListing.java @@ -122,6 +122,6 @@ public static org.apache.poi.hslf.record.Record findRecordAtPos(int pos) { long type = LittleEndian.getUShort(fileContents, pos+2); long rlen = LittleEndian.getUInt(fileContents, pos+4); - return Record.createRecordForType(type,fileContents,pos,Math.toIntExact(rlen+8)); + return Record.createRecordForType(type,fileContents,pos,(int)rlen+8); } } From 8da7bdc13bed04bffd134b0d9bc1360dd12a2e6f Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 Jun 2026 22:09:51 +0100 Subject: [PATCH 3/4] try to fix skip issues --- .../org/apache/poi/hemf/record/emf/HemfComment.java | 2 +- .../org/apache/poi/hemf/record/emf/HemfHeader.java | 2 +- .../poi/hemf/record/emf/HemfRecordIterator.java | 2 +- .../org/apache/poi/util/LittleEndianInputStream.java | 11 +++++++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java index ff9d0f48a98..2aeaa3716cd 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java @@ -247,7 +247,7 @@ private EmfCommentData _next() { final EmfCommentData record = commentType.constructor.get(); long readBytes = record.init(leis, dataSize); - final int skipBytes = Math.toIntExact(recordSize-4-readBytes); + final long skipBytes = recordSize-4-readBytes; assert (skipBytes >= 0); leis.skipFully(skipBytes); 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 f9f8943e8d9..3ecb2eed84a 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 @@ -167,7 +167,7 @@ public long init(LittleEndianInputStream leis, long recordSize, long recordId) t size += readDimensionInt(leis, milliDimension); if (nDescription > 0 && offDescription > 0) { - int skip = Math.toIntExact(offDescription - (size + HEADER_SIZE)); + long skip = offDescription - (size + HEADER_SIZE); long descriptionBytes = (nDescription - 1) * LittleEndianConsts.SHORT_SIZE; long descriptionEnd = offDescription + nDescription * LittleEndianConsts.SHORT_SIZE; if (skip < 0 || descriptionEnd > recordSize + HEADER_SIZE || skip + descriptionBytes > Integer.MAX_VALUE) { diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java index 69330553906..dc2ca7118f4 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecordIterator.java @@ -81,7 +81,7 @@ private HemfRecord _next() { if (readBytes > remBytes) { throw new RecordFormatException("Record limit exceeded - readBytes: "+readBytes+" / remBytes: "+remBytes); } - stream.skipFully(Math.toIntExact(remBytes - readBytes)); + stream.skipFully(remBytes - readBytes); } catch (RecordFormatException e) { throw e; } catch (IOException|RuntimeException e) { diff --git a/poi/src/main/java/org/apache/poi/util/LittleEndianInputStream.java b/poi/src/main/java/org/apache/poi/util/LittleEndianInputStream.java index cc2c3b927f9..204a5aa5f20 100644 --- a/poi/src/main/java/org/apache/poi/util/LittleEndianInputStream.java +++ b/poi/src/main/java/org/apache/poi/util/LittleEndianInputStream.java @@ -216,4 +216,15 @@ public void skipFully(int len) throws IOException { } checkEOF((int)skipped, len); } + + public void skipFully(long len) throws IOException { + if (len == 0) { + return; + } + long skipped = IOUtils.skipFully(this, len); + if (skipped > Integer.MAX_VALUE) { + throw new IOException("can't skip further than "+Integer.MAX_VALUE); + } + checkEOF((int)skipped, (int)len); + } } From 02ac085fe8a987f94e3e58d819081c5acb1b421c Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 Jun 2026 22:34:09 +0100 Subject: [PATCH 4/4] Update poi-integration-exceptions.csv --- test-data/poi-integration-exceptions.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/poi-integration-exceptions.csv b/test-data/poi-integration-exceptions.csv index 9244a0337b9..f38fec98ff7 100644 --- a/test-data/poi-integration-exceptions.csv +++ b/test-data/poi-integration-exceptions.csv @@ -375,7 +375,7 @@ spreadsheet/rde.imf.ru_sites_default_files_rde_documents_vodootvedenie_2020.xlsb spreadsheet/crash-e329fca9087fe21bca4a80c8bc472a661c98d860.xls,handle,HSSF,,org.apache.poi.util.RecordFormatException,33198 bytes written but getRecordSize() reports 33194, slideshow/61338.wmf,"handle,extract",HWMF,,org.apache.poi.util.RecordFormatException,Tried to skip 9699347 but skipped: 489, slideshow/file-45.wmf,handle,HWMF,,org.apache.poi.util.RecordFormatException,The width or height specified in the header exceed the current limit, -spreadsheet/61294.emf,"handle,extract",HEMF,,org.apache.poi.util.RecordFormatException,java.lang.IllegalArgumentException: Skip count must be non-negative, +spreadsheet/61294.emf,"handle,extract",HEMF,,org.apache.poi.util.RecordFormatException,java.lang.IllegalStateException: Unexpected end-of-file, publisher/clusterfuzz-testcase-minimized-POIHPBFFuzzer-6325615354773504.pub,"handle,extract",HPBF,,java.lang.IllegalArgumentException,File invalid - failed to find document entry, slideshow/clusterfuzz-testcase-minimized-POIXSLFFuzzer-6071540680032256.pptx,extract,"XSLF,OPC",,java.lang.IllegalStateException,"Invalid content in diagram, cannot extract text", slideshow/clusterfuzz-testcase-minimized-POIXSLFFuzzer-6071540680032256.pptx,handle,XSLF,,java.lang.IllegalStateException,SlideMaster was not found for Name,