New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FLINK-6162]Fix bug in ByteArrayOutputStreamWithPos#setPosition #3595
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is not using the array. The only method depending on a positively bounded count
is toString
.
public class ByteArrayOutputStreamWithPosTest { | ||
@Test | ||
public void setPositionWhenBufferIsFull() throws Exception { | ||
ByteArrayOutputStreamWithPos stream = new ByteArrayOutputStreamWithPos(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialize with a constant size matching the next line.
@greghogan thanks for the review, I have changed the change test to use explicit buffer size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add some tests since currently we are only checking that no exception is thrown.
public class ByteArrayOutputStreamWithPosTest { | ||
@Test | ||
public void setPositionWhenBufferIsFull() throws Exception { | ||
ByteArrayOutputStreamWithPos stream = new ByteArrayOutputStreamWithPos(32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is stronger to replace 32
on these lines with a descriptive local variable. After initialization could add an assertion that getBuf().length
equals that value.
public void setPositionWhenBufferIsFull() throws Exception { | ||
ByteArrayOutputStreamWithPos stream = new ByteArrayOutputStreamWithPos(32); | ||
stream.write(new byte[32]); | ||
stream.setPosition(stream.getPosition()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert that getPosition
is equal to the expected value. Can validate that setPosition
now works per the change above and does not change the position, and also check that toString
can be executed.
@greghogan comments addressed |
I would suggest to introduce the analogue check also in |
hi, @StefanRRichter , I have add check in setPosition in ByteArrayInputSteamWithPos, there is no dependency on this method too, so I rename the method from setPos to setPosition for unifying. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also call ByteArrayOutputStreamWithPos#toString()
at the end of the test (I don't think the output matters, but the call will test that the bounds are consistent).
@@ -118,7 +118,8 @@ public int getPosition() { | |||
return position; | |||
} | |||
|
|||
public void setPos(int pos) { | |||
public void setPosition(int pos) { | |||
Preconditions.checkArgument(pos < count, "Position out of bounds."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow for equality as with ByteArrayOutputStreamWithPos
? And check for non-negative. Should we create a matching getEndPosition()
as in ByteArrayOutputStreamWithPos
?
@@ -110,7 +110,7 @@ public int getPosition() { | |||
} | |||
|
|||
public void setPosition(int position) { | |||
Preconditions.checkArgument(position < getEndPosition(), "Position out of bounds."); | |||
Preconditions.checkArgument(position <= getEndPosition(), "Position out of bounds."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for non-negative.
/** | ||
* This tests that the expected position exceeds the capacity of the byte array. | ||
*/ | ||
@Test(expected = IllegalArgumentException.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the preference is to instead use ExpectedException
which can also take an expected message.
@greghogan Thanks for the review. I have add non-negative check and update the test with ExpectedException. But I don't think we need to call toString in the test since we have check the position instead I add a test to verify that toString returns the substring with range(0, position) to meet your concern. One update about setPosition in outputStream, I think it is better to auto extend the buffer when setting a position larger than the buffer size, just like the auto extending in write. |
When expanding with |
@greghogan Currently we check the position with the EndPosition which is the size of buffer instead of a max written size , so it is still possible to leave holes when keeping unmodified. Enabling auto extending can give the user the flexibility to reserved some space for later filling and does not change current functions logics. |
@wenlong88 you are right that the position can currently be moved beyond written data. This still feels a bit like feature creep as we've added to the PR. Do you need to expand the array is this manner? How did you run across this bug? I'm not disagreeing with the change but would like to be conservative and understand the why. |
@greghogan I come across this bug when we are trying to write some objects to a byte array: at first, I wrote a 0 as initial size and then the serialized object, after that, I seek back to the start position to correct the size and then seek to the end of the written data to continue to write other object. When the array can auto expanding, I can just reserve some hole at first and then seek back and fill the hole. |
hi, @greghogan , do you have any new comment about the changes? |
Fix off-by-one error in 'setPosition' and expand array when seeking outside the original bounds. This closes apache#3595
@wenlong88 thanks for the contribution (and the ping)! Merging ... |
Fix off-by-one error in 'setPosition' and expand array when seeking outside the original bounds. This closes apache#3595
Currently the precondition check in setPosition will fail when the buffer is full:
{{Preconditions.checkArgument(position < getEndPosition(), "Position out of bounds.");}}
We should allow the expected position to be the end position
I have added a test on the fix.