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 2d79abc001 guard XSSFBUtils wide-string byte length against int 
overflow (#1079)
2d79abc001 is described below

commit 2d79abc0017c96d29c6367a8c255876fc584e535
Author: jmestwa-coder <[email protected]>
AuthorDate: Wed May 27 18:50:21 2026 +0530

    guard XSSFBUtils wide-string byte length against int overflow (#1079)
    
    * guard XSSFBUtils wide-string byte length against int overflow
    
    * use checked narrowing for numBytes in XSSFBUtils string append
---
 .../org/apache/poi/xssf/binary/XSSFBUtils.java     | 14 ++---
 .../org/apache/poi/xssf/binary/TestXSSFBUtils.java | 72 ++++++++++++++++++++++
 2 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBUtils.java 
b/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBUtils.java
index cef9e6807f..a17a989fc7 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBUtils.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBUtils.java
@@ -47,15 +47,14 @@ public class XSSFBUtils {
             throw new XSSFBParseException("too many chars to read");
         }
 
-        int numBytes = 2*(int)numChars;
+        long numBytes = 2L*numChars;
         offset += 4;
         if (offset+numBytes > data.length) {
             throw new XSSFBParseException("trying to read beyond data length: 
" +
              "offset="+offset+", numBytes="+numBytes+", 
data.length="+data.length);
         }
-        sb.append(new String(data, offset, numBytes, 
StandardCharsets.UTF_16LE));
-        numBytes+=4;
-        return numBytes;
+        sb.append(new String(data, offset, Math.toIntExact(numBytes), 
StandardCharsets.UTF_16LE));
+        return Math.toIntExact(numBytes+4);
     }
 
 
@@ -74,14 +73,13 @@ public class XSSFBUtils {
         } else if (numChars > 0xFFFFFFFFL) {
             throw new XSSFBParseException("too many chars to read");
         }
-        int numBytes = 2*(int)numChars;
+        long numBytes = 2L*numChars;
         offset += 4;
         if (offset+numBytes > data.length) {
             throw new XSSFBParseException("trying to read beyond data length");
         }
-        sb.append(new String(data, offset, numBytes, 
StandardCharsets.UTF_16LE));
-        numBytes+=4;
-        return numBytes;
+        sb.append(new String(data, offset, Math.toIntExact(numBytes), 
StandardCharsets.UTF_16LE));
+        return Math.toIntExact(numBytes+4);
     }
 
 
diff --git 
a/poi-ooxml/src/test/java/org/apache/poi/xssf/binary/TestXSSFBUtils.java 
b/poi-ooxml/src/test/java/org/apache/poi/xssf/binary/TestXSSFBUtils.java
new file mode 100644
index 0000000000..2856f9f189
--- /dev/null
+++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/binary/TestXSSFBUtils.java
@@ -0,0 +1,72 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.binary;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.apache.poi.util.LittleEndian;
+import org.junit.jupiter.api.Test;
+
+class TestXSSFBUtils {
+
+    /**
+     * A char count whose doubled byte length exceeds Integer.MAX_VALUE used to
+     * be narrowed via {@code 2*(int)numChars}, wrapping to a negative value 
that
+     * slipped past the {@code offset+numBytes > data.length} check and 
surfaced
+     * as a bare StringIndexOutOfBoundsException. The bounds check must reject 
it
+     * with an XSSFBParseException instead.
+     */
+    @Test
+    void rejectsOversizedWideString() {
+        byte[] data = new byte[100];
+        LittleEndian.putUInt(data, 0, 0x40000000L); // ~1G chars -> 2G bytes
+
+        assertThrows(XSSFBParseException.class,
+                () -> XSSFBUtils.readXLWideString(data, 0, new 
StringBuilder()));
+        assertThrows(XSSFBParseException.class,
+                () -> XSSFBUtils.readXLNullableWideString(data, 0, new 
StringBuilder()));
+    }
+
+    /**
+     * A char count above 0x7FFFFFFF used to overflow to a small positive
+     * numBytes, silently reading the wrong length and desyncing the record
+     * stream. It must be rejected by the same bounds check.
+     */
+    @Test
+    void rejectsHighBitWideString() {
+        byte[] data = new byte[100];
+        LittleEndian.putUInt(data, 0, 0x80000001L);
+
+        assertThrows(XSSFBParseException.class,
+                () -> XSSFBUtils.readXLWideString(data, 0, new 
StringBuilder()));
+    }
+
+    @Test
+    void readsValidWideString() throws Exception {
+        byte[] str = 
"POI".getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
+        byte[] data = new byte[4 + str.length];
+        LittleEndian.putUInt(data, 0, 3L);
+        System.arraycopy(str, 0, data, 4, str.length);
+
+        StringBuilder sb = new StringBuilder();
+        int read = XSSFBUtils.readXLWideString(data, 0, sb);
+        assertEquals("POI", sb.toString());
+        assertEquals(data.length, read);
+    }
+}


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

Reply via email to