Fix infinite loops in ObservableInputStream read(*) when an exception is
caught but not re-thrown.
MODIFY
src/changes/changes.xml
src/changes/changes.xml
@@ -108,6 +108,9 @@ The <action> type attribute can be add,update,fix,remove.
<action issue="IO-705" dev="ggregory" type="fix" due-to="Hao Zhong, Gary Gregory">
LockableFileWriter.close() should fail when the lock file cannot be deleted.
</action>
+ <action issue="IO-705" dev="ggregory" type="fix" due-to="Hao Zhong, Gary Gregory">
+ Fix infinite loops in ObservableInputStream read(*) when an exception is caught but not re-thrown.
+ </action>
<!-- ADD -->
<action dev="ggregory" type="add" due-to="Gary Gregory">
Add FileSystemProviders class.

MODIFY
src/main/java/org/apache/commons/io/input/ObservableInputStream.java
src/main/java/org/apache/commons/io/input/ObservableInputStream.java
@@ -244,6 +244,7 @@ protected void noteFinished() throws IOException {
private void notify(final byte[] buffer, final int offset, int result, IOException ioe) throws IOException {
if (ioe != null) {
noteError(ioe);
+ throw ioe;
} else if (result == EOF) {
noteFinished();
} else if (result > 0) {
@@ -257,11 +258,12 @@ public int read() throws IOException {
IOException ioe = null;
try {
result = super.read();
- } catch (final IOException pException) {
- ioe = pException;
+ } catch (final IOException ex) {
+ ioe = ex;
}
if (ioe != null) {
noteError(ioe);
+ throw ioe;
} else if (result == EOF) {
noteFinished();
} else {
@@ -276,8 +278,8 @@ public int read(final byte[] buffer) throws IOException {
IOException ioe = null;
try {
result = super.read(buffer);
- } catch (final IOException pException) {
- ioe = pException;
+ } catch (final IOException ex) {
+ ioe = ex;
}
notify(buffer, 0, result, ioe);
return result;
@@ -289,8 +291,8 @@ public int read(final byte[] buffer, final int offset, final int length) throws
IOException ioe = null;
try {
result = super.read(buffer, offset, length);
- } catch (final IOException pException) {
- ioe = pException;
+ } catch (final IOException ex) {
+ ioe = ex;
}
notify(buffer, offset, result, ioe);
return result;

MODIFY
src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java
src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -125,6 +126,27 @@ public long getFinishedCount() {
}
+ @Test
+ public void testBrokenInputStreamRead() throws IOException {
+ try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
+ assertThrows(IOException.class, () -> ois.read());
+ }
+ }
+
+ @Test
+ public void testBrokenInputStreamReadBuffer() throws IOException {
+ try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
+ assertThrows(IOException.class, () -> ois.read(new byte[1]));
+ }
+ }
+
+ @Test
+ public void testBrokenInputStreamReadSubBuffer() throws IOException {
+ try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
+ assertThrows(IOException.class, () -> ois.read(new byte[2], 0, 1));
+ }
+ }
+
/**
* Tests that {@link Observer#data(int)} is called.
*/

Fix infinite loops in ObservableInputStream read(*) when an exception is
caught but not re-thrown.