Author: centic
Date: Tue Jul 16 13:26:16 2024
New Revision: 1919284

URL: http://svn.apache.org/viewvc?rev=1919284&view=rev
Log:
Bug 66425: Avoid exceptions found via poi-fuzz

Avoid a possible OutOfMemoryException with incorrect uniqueCount

The ReadOnlySharedStringsTable pre-allocates whatever is stated in uniqueCount.

As the uniqueCount may be an incorrect large number, we should cap it at some 
point
to avoid OOMs if corrupt files are processed.

Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66137

Modified:
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestReadOnlySharedStringsTable.java

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java?rev=1919284&r1=1919283&r2=1919284&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java
 Tue Jul 16 13:26:16 2024
@@ -248,7 +248,10 @@ public class ReadOnlySharedStringsTable
             String uniqueCount = attributes.getValue("uniqueCount");
             if(uniqueCount != null) this.uniqueCount = (int) 
Long.parseLong(uniqueCount);
 
-            this.strings = new ArrayList<>(this.uniqueCount);
+            this.strings = new ArrayList<>(
+                    // corrupted files may have a very large number here, so 
only use it
+                    // up to some size as guideline for pre-allocating the list
+                    Math.min(this.uniqueCount, 100_000));
             characters = new StringBuilder(64);
         } else if ("si".equals(localName)) {
             if (characters != null) {

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestReadOnlySharedStringsTable.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestReadOnlySharedStringsTable.java?rev=1919284&r1=1919283&r2=1919284&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestReadOnlySharedStringsTable.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestReadOnlySharedStringsTable.java
 Tue Jul 16 13:26:16 2024
@@ -20,10 +20,14 @@
 package org.apache.poi.xssf.eventusermodel;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -160,4 +164,39 @@ public final class TestReadOnlySharedStr
         assertEquals(0, sst.getCount());
         assertEquals(0, sst.getUniqueCount());
     }
+
+    private static final String MINIMAL_XML = "<?xml version=\"1.0\" 
encoding=\"UTF-8\" standalone=\"yes\"?>" +
+            "<sst 
xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"; 
count=\"55\" uniqueCount=\"49\">" +
+            "<si>" +
+            "<t>bla</t>" +
+            "<phoneticPr fontId=\"1\"/>" +
+            "</si>" +
+            "</sst>";
+
+    @Test
+    void testMinimalTable() throws IOException, SAXException {
+        ReadOnlySharedStringsTable tbl = new ReadOnlySharedStringsTable(
+                new 
ByteArrayInputStream(MINIMAL_XML.getBytes(StandardCharsets.UTF_8)));
+        assertNotNull(tbl);
+        assertEquals(49, tbl.getUniqueCount());
+        assertEquals(55, tbl.getCount());
+        assertTrue(tbl.includePhoneticRuns);
+        assertEquals("bla", tbl.getItemAt(0).getString());
+        assertThrows(IllegalStateException.class,
+                () -> tbl.getItemAt(1).getString());
+    }
+
+    @Test
+    void testHugeUniqueCount() throws IOException, SAXException {
+        ReadOnlySharedStringsTable tbl = new ReadOnlySharedStringsTable(
+                new ByteArrayInputStream(MINIMAL_XML.replace("49", 
"99999999999999999").
+                        getBytes(StandardCharsets.UTF_8)));
+        assertNotNull(tbl);
+        assertEquals(1569325055, tbl.getUniqueCount());
+        assertEquals(55, tbl.getCount());
+        assertTrue(tbl.includePhoneticRuns);
+        assertEquals("bla", tbl.getItemAt(0).getString());
+        assertThrows(IllegalStateException.class,
+                () -> tbl.getItemAt(1).getString());
+    }
 }



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

Reply via email to