Skip to content

Commit

Permalink
Bug 66425: Avoid exceptions found via poi-fuzz
Browse files Browse the repository at this point in the history
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

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1919284 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
centic9 committed Jul 16, 2024
1 parent cc4fbe1 commit 7b15aef
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,10 @@ public void startElement(String uri, String localName, String name,
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -160,4 +164,39 @@ private void assertEmptySST(OPCPackage pkg) throws IOException, SAXException {
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());
}
}

0 comments on commit 7b15aef

Please sign in to comment.