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 d32685729a31874319aa6cb59c7636b8c7ddae52 Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Sun Sep 26 10:58:58 2021 -0400 [IO-717] Infinite loop in ReaderInputStream instead of throwing exception for CodingErrorAction.REPORT. --- src/changes/changes.xml | 3 +++ .../apache/commons/io/input/ReaderInputStream.java | 3 +++ .../commons/io/input/ReaderInputStreamTest.java | 25 ++++++++++++++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b0c6580..ff5fda0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -92,6 +92,9 @@ The <action> type attribute can be add,update,fix,remove. <action issue="IO-721" dev="ggregory" type="fix" due-to="Dirk Heinrichs, Gary Gregory"> Wrong exception message in FileUtils.setLastModified(File, File). </action> + <action issue="IO-717" dev="ggregory" type="fix" due-to="Marcono1234, Gary Gregory"> + Infinite loop in ReaderInputStream instead of throwing exception for CodingErrorAction.REPORT. + </action> <!-- ADD --> <action dev="ggregory" type="add" due-to="Gary Gregory"> Add BrokenReader.INSTANCE. diff --git a/src/main/java/org/apache/commons/io/input/ReaderInputStream.java b/src/main/java/org/apache/commons/io/input/ReaderInputStream.java index 5e4b3db..860043f 100644 --- a/src/main/java/org/apache/commons/io/input/ReaderInputStream.java +++ b/src/main/java/org/apache/commons/io/input/ReaderInputStream.java @@ -228,6 +228,9 @@ public class ReaderInputStream extends InputStream { } encoderOut.compact(); lastCoderResult = encoder.encode(encoderIn, encoderOut, endOfInput); + if (lastCoderResult.isError()) { + lastCoderResult.throwException(); + } encoderOut.flip(); } diff --git a/src/test/java/org/apache/commons/io/input/ReaderInputStreamTest.java b/src/test/java/org/apache/commons/io/input/ReaderInputStreamTest.java index d6ca4a4..b9eff9c 100644 --- a/src/test/java/org/apache/commons/io/input/ReaderInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/ReaderInputStreamTest.java @@ -18,15 +18,22 @@ package org.apache.commons.io.input; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.CharArrayReader; import java.io.IOException; +import java.io.InputStream; import java.io.StringReader; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.util.Random; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; public class ReaderInputStreamTest { private static final String TEST_STRING = "\u00e0 peine arriv\u00e9s nous entr\u00e2mes dans sa chambre"; @@ -34,7 +41,7 @@ public class ReaderInputStreamTest { static { final StringBuilder buffer = new StringBuilder(); - for (int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { buffer.append(TEST_STRING); } LARGE_TEST_STRING = buffer.toString(); @@ -48,7 +55,7 @@ public class ReaderInputStreamTest { @Test public void testCharsetMismatchInfiniteLoop() throws IOException { // Input is UTF-8 bytes: 0xE0 0xB2 0xA0 - final char[] inputChars = { (char) 0xE0, (char) 0xB2, (char) 0xA0 }; + final char[] inputChars = {(char) 0xE0, (char) 0xB2, (char) 0xA0}; // Charset charset = Charset.forName("UTF-8"); // works final Charset charset = StandardCharsets.US_ASCII; // infinite loop try (ReaderInputStream stream = new ReaderInputStream(new CharArrayReader(inputChars), charset)) { @@ -57,6 +64,20 @@ public class ReaderInputStreamTest { } } + /** + * Tests IO-717 to avoid infinite loops. + * + * ReaderInputStream does not throw exception with {@link CodingErrorAction#REPORT}. + */ + @Test + @Timeout(value = 500, unit = TimeUnit.MILLISECONDS) + public void testCodingErrorAction() throws IOException { + CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder().onMalformedInput(CodingErrorAction.REPORT); + try (InputStream in = new ReaderInputStream(new StringReader("\uD800aa"), encoder, 2)) { + assertThrows(CharacterCodingException.class, in::read); + } + } + @Test public void testLargeUTF8WithBufferedRead() throws IOException { testWithBufferedRead(LARGE_TEST_STRING, "UTF-8");