Skip to content

Commit

Permalink
Fix infinite loop in PackedInputStream when the supplied ArrayInputSt…
Browse files Browse the repository at this point in the history
…ream is smaller than needed

Additionally:
* ArrayInputStream is no longer final, as there is no reason to stop consumers from extending and adjusting the behaviour
*  The wrapped ByteBuffer is not private, as according to the (previously) undocumented contract, it should be only accessible through #getReadBuffer().
  • Loading branch information
mdindoffer committed Jun 4, 2024
1 parent ed9a67c commit 63972b2
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 5 deletions.
11 changes: 7 additions & 4 deletions runtime/src/main/java/org/capnproto/ArrayInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;

public final class ArrayInputStream implements BufferedInputStream {
public class ArrayInputStream implements BufferedInputStream {

public final ByteBuffer buf;
private final ByteBuffer buf;

public ArrayInputStream(ByteBuffer buf) {
this.buf = buf.asReadOnlyBuffer();
Expand All @@ -52,7 +51,11 @@ public final int read(ByteBuffer dst) throws IOException {

@Override
public final ByteBuffer getReadBuffer() {
return this.buf;
if (buf.remaining() > 0) {
return buf;
} else {
throw new DecodeException("Premature EOF while reading buffer");
}
}

@Override
Expand Down
11 changes: 10 additions & 1 deletion runtime/src/main/java/org/capnproto/BufferedInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,14 @@
import java.nio.channels.ReadableByteChannel;

public interface BufferedInputStream extends ReadableByteChannel {
public ByteBuffer getReadBuffer() throws java.io.IOException;

/**
* Returns a {@link ByteBuffer} to read data from.
* If there is no more data to read, throws a {@link DecodeException}.
*
* @return a {@link ByteBuffer} with data to read from, if any available
* @throws java.io.IOException when an I/O error occurs
* @throws DecodeException when trying to read more data than available
*/
ByteBuffer getReadBuffer() throws java.io.IOException;
}
12 changes: 12 additions & 0 deletions runtime/src/test/java/org/capnproto/SerializePackedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,16 @@ private void assertPacksTo(byte[] unpacked, byte[] packed) {
Assert.assertTrue(Arrays.equals(bytes, unpacked));
}
}

@Test(timeout = 1000, expected = DecodeException.class)
public void read_shouldThrowDecodingExceptionOnEmptyArrayInputStream() throws IOException {
byte[] emptyByteArray = {};
MessageReader reader = SerializePacked.read(new ArrayInputStream(ByteBuffer.wrap(emptyByteArray)), ReaderOptions.DEFAULT_READER_OPTIONS);
}

@Test(timeout = 1000, expected = DecodeException.class)
public void read_shouldThrowDecodingExceptionWhenTryingToReadMoreThanAvailableFromArrayInputStream() throws IOException {
byte[] bytes = {17, 0, 127, 0, 0, 0, 0}; //segment0 size of 127 words, which is way larger than the tiny 7 byte input
MessageReader reader = SerializePacked.read(new ArrayInputStream(ByteBuffer.wrap(bytes)), ReaderOptions.DEFAULT_READER_OPTIONS);
}
}

0 comments on commit 63972b2

Please sign in to comment.