This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git

commit 7e0d317ac61427e6004372622df4014c1e602487
Author: Gary Gregory <gardgreg...@gmail.com>
AuthorDate: Sun May 16 10:26:40 2021 -0400

    [IO-429] Check for long streams in IOUtils.toByteArray #175.
---
 src/changes/changes.xml                                  |  3 +++
 src/main/java/org/apache/commons/io/IOUtils.java         | 14 ++++++++++----
 src/test/java/org/apache/commons/io/IOUtilsTestCase.java |  9 +++++++++
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3bdcbbb..87524e3 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -126,6 +126,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="fix" due-to="Rob Spoor, Gary Gregory">
         Prevent infinite loop with AbstractCharacterFilterReader if EOF is 
filtered out #226.
       </action>
+      <action issue="IO-429" dev="ggregory" type="fix" due-to="Rob Spoor, Ivan 
Leskin">
+        Check for long streams in IOUtils.toByteArray #175.
+      </action>
       <!-- ADD -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add FileSystemProviders class.
diff --git a/src/main/java/org/apache/commons/io/IOUtils.java 
b/src/main/java/org/apache/commons/io/IOUtils.java
index eaf5856..624d7a0 100644
--- a/src/main/java/org/apache/commons/io/IOUtils.java
+++ b/src/main/java/org/apache/commons/io/IOUtils.java
@@ -55,6 +55,7 @@ import org.apache.commons.io.output.AppendableWriter;
 import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.commons.io.output.NullOutputStream;
 import org.apache.commons.io.output.StringBuilderWriter;
+import org.apache.commons.io.output.ThresholdingOutputStream;
 import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
 
 /**
@@ -2394,12 +2395,17 @@ public class IOUtils {
      * @param inputStream the {@code InputStream} to read.
      * @return the requested byte array.
      * @throws NullPointerException if the InputStream is {@code null}.
-     * @throws IOException if an I/O error occurs.
+     * @throws IOException if an I/O error occurs or reading more than {@link 
Integer#MAX_VALUE} occurs. 
      */
     public static byte[] toByteArray(final InputStream inputStream) throws 
IOException {
-        try (final UnsynchronizedByteArrayOutputStream output = new 
UnsynchronizedByteArrayOutputStream()) {
-            copy(inputStream, output);
-            return output.toByteArray();
+        // We use a ThresholdingOutputStream to avoid reading AND writing more 
than Integer.MAX_VALUE.
+        try (final UnsynchronizedByteArrayOutputStream ubaOutput = new 
UnsynchronizedByteArrayOutputStream();
+            final ThresholdingOutputStream thresholdOuput = new 
ThresholdingOutputStream(Integer.MAX_VALUE, os -> {
+                throw new IllegalArgumentException(
+                    String.format("Cannot read more than %,d into a byte 
array", Integer.MAX_VALUE));
+            }, os -> ubaOutput)) {
+            copy(inputStream, thresholdOuput);
+            return ubaOutput.toByteArray();
         }
     }
 
diff --git a/src/test/java/org/apache/commons/io/IOUtilsTestCase.java 
b/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
index 5e89881..106729b 100644
--- a/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
@@ -62,6 +62,7 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.io.function.IOConsumer;
+import org.apache.commons.io.input.CircularInputStream;
 import org.apache.commons.io.input.NullInputStream;
 import org.apache.commons.io.output.AppendableWriter;
 import org.apache.commons.io.output.NullOutputStream;
@@ -69,6 +70,7 @@ import org.apache.commons.io.output.StringBuilderWriter;
 import org.apache.commons.io.test.TestUtils;
 import org.apache.commons.io.test.ThrowOnCloseReader;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
@@ -1436,6 +1438,13 @@ public class IOUtilsTestCase {
     }
 
     @Test
+    @Disabled("Disable by default as it uses too much memory and can cause 
builds to fail.")
+    public void testToByteArray_InputStream_LongerThanIntegerMaxValue() throws 
Exception {
+        final CircularInputStream cin = new 
CircularInputStream(IOUtils.byteArray(), Integer.MAX_VALUE + 1L);
+        assertThrows(IllegalArgumentException.class, () -> 
IOUtils.toByteArray(cin));
+    }
+
+    @Test
     public void testToByteArray_InputStream_NegativeSize() throws Exception {
 
         try (FileInputStream fin = new FileInputStream(testFile)) {

Reply via email to