Do not use buffer limit as indicator of frame completion.

If the frame happens to be exactly the same size as the buffer capacity, we
will erroneously think that the last frame was complete because the limit is
normally at the buffer capacity.

This only exploded when we had both a perfectly sized frame and failed to read
it in a single call to read, which apparently took 17 years to happen, and many
billions of frames read.
This commit is contained in:
Michael Bayne
2018-09-26 15:14:14 -07:00
parent ed7c071de1
commit 11e815fcc3
@@ -80,7 +80,9 @@ public class FramedInputStream extends InputStream
throws IOException throws IOException
{ {
// flush data from any previous frame from the buffer // flush data from any previous frame from the buffer
if (_buffer.limit() == _length) { if (_haveCompleteFrame) {
_haveCompleteFrame = false;
// this will remove the old frame's bytes from the buffer, // this will remove the old frame's bytes from the buffer,
// shift our old data to the start of the buffer, position the // shift our old data to the start of the buffer, position the
// buffer appropriately for appending new data onto the end of // buffer appropriately for appending new data onto the end of
@@ -179,6 +181,7 @@ public class FramedInputStream extends InputStream
// prepare the buffer such that this frame can be read // prepare the buffer such that this frame can be read
_buffer.position(HEADER_SIZE); _buffer.position(HEADER_SIZE);
_buffer.limit(_length); _buffer.limit(_length);
_haveCompleteFrame = true;
return true; return true;
} }
@@ -312,6 +315,9 @@ public class FramedInputStream extends InputStream
* may comprise more than one frame. */ * may comprise more than one frame. */
protected int _have = 0; protected int _have = 0;
/** Tracks whether we read a complete frame in our last call to {@link #readFrame}. */
protected boolean _haveCompleteFrame;
/** The size of the frame header (a 32-bit integer). */ /** The size of the frame header (a 32-bit integer). */
protected static final int HEADER_SIZE = 4; protected static final int HEADER_SIZE = 4;