Fix infinite loop in PackedInputStream when the supplied ArrayInputStream 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().
This commit is contained in:
Martin Dindoffer 2024-06-04 14:31:37 +02:00 committed by Semisol
parent e570a6ce70
commit de1e334091
Signed by: Semisol
GPG key ID: 0949D3C25C7FD14F
3 changed files with 29 additions and 5 deletions

View file

@ -23,11 +23,10 @@ package org.capnproto;
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();
@ -52,7 +51,11 @@ public final class ArrayInputStream implements BufferedInputStream {
@Override
public final ByteBuffer getReadBuffer() {
return this.buf;
if (buf.remaining() > 0) {
return buf;
} else {
throw new DecodeException("Premature EOF while reading buffer");
}
}
@Override

View file

@ -25,5 +25,14 @@ import java.nio.ByteBuffer;
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;
}

View file

@ -82,4 +82,16 @@ public class SerializePackedTest {
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);
}
}