From 66109187d12b72696ea02101cec765d77d9bbdc9 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Sun, 18 Jan 2026 16:49:58 +0100 Subject: [PATCH] Only allocate the required size for EscherComplexProperty Otherwise a malformed document can cause OOM by reserving large chunks of memory, but only using little of it. This fixes https://issues.oss-fuzz.com/issues/476184826 --- .../apache/poi/ddf/EscherComplexProperty.java | 18 +++++++++++------- ...nimized-POIHPBFFuzzer-6325615354773504.pub | Bin 0 -> 2042 bytes test-data/spreadsheet/stress.xls | Bin 76800 -> 76800 bytes 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 test-data/publisher/clusterfuzz-testcase-minimized-POIHPBFFuzzer-6325615354773504.pub diff --git a/poi/src/main/java/org/apache/poi/ddf/EscherComplexProperty.java b/poi/src/main/java/org/apache/poi/ddf/EscherComplexProperty.java index 356cd4a8c4..680ee9a5ae 100644 --- a/poi/src/main/java/org/apache/poi/ddf/EscherComplexProperty.java +++ b/poi/src/main/java/org/apache/poi/ddf/EscherComplexProperty.java @@ -67,9 +67,9 @@ public class EscherComplexProperty extends EscherProperty { this.complexSize = complexSize; } - private void ensureComplexData() { + private void ensureComplexData(int size) { if (this.complexData == null) { - complexData = IOUtils.safelyAllocate(complexSize, MAX_RECORD_LENGTH); + complexData = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH); } } @@ -131,7 +131,9 @@ public class EscherComplexProperty extends EscherProperty { * @return the complex bytes */ public byte[] getComplexData() { - ensureComplexData(); + // we need to allocate here as sometimes the array is written to + ensureComplexData(complexSize); + return complexData; } @@ -147,8 +149,8 @@ public class EscherComplexProperty extends EscherProperty { if (complexData == null) { return 0; } else { - ensureComplexData(); - int copySize = Math.max(0, Math.min(this.complexData.length, complexData.length - offset)); + int copySize = Math.max(0, Math.min(complexSize, complexData.length - offset)); + ensureComplexData(copySize); System.arraycopy(complexData, offset, this.complexData, 0, copySize); return copySize; } @@ -165,6 +167,8 @@ public class EscherComplexProperty extends EscherProperty { // no need to copy if data was not initialized yet if (complexData == null) { + complexSize = newSize; + return; } @@ -218,13 +222,13 @@ public class EscherComplexProperty extends EscherProperty { @Override public int hashCode() { - ensureComplexData(); + ensureComplexData(complexSize); return Arrays.deepHashCode(new Object[]{complexData, getId()}); } @Override public Map> getGenericProperties() { - ensureComplexData(); + ensureComplexData(complexSize); return GenericRecordUtil.getGenericProperties( "base", super::getGenericProperties, "data", this::getComplexData diff --git a/test-data/publisher/clusterfuzz-testcase-minimized-POIHPBFFuzzer-6325615354773504.pub b/test-data/publisher/clusterfuzz-testcase-minimized-POIHPBFFuzzer-6325615354773504.pub new file mode 100644 index 0000000000000000000000000000000000000000..99c698207fa7edc05e2bfc72470a06acc81137ce GIT binary patch literal 2042 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 V{Yh4DpgWCsaULJIv5JQT{STEb==A^q