-
-
Notifications
You must be signed in to change notification settings - Fork 144
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
Hazard with ReadBytesExt
methods and continuing after errors
#208
Comments
Thanks for the write-up. I'm fine adding a note to the docs. Patches welcome. I'm not sure |
I agree for I also have sympathy for anyone that missed this detail, because a I think that perhaps rust-lang/rust#125123 is the change that modified the example's behavior under 1.80.0. The change occurs between |
std::io::Read::read_exact documentation says that if an error occurs, the state of the reader is unspecified: it may have consumed some number of bytes (between zero and the size of the buffer). This makes it unwise to continue reading after an error, since it's not possible to know where the read begins. A caller may be surprised by this issue, for example by calling read_u16() until it fails, then calling read_u8() to collect a remainder byte. This is not guaranteed to work. This was specifically observed to behave one way on rust 1.79.0, and then a different way in rust 1.80.0 when using std::io::Cursor as the reader. Closes BurntSushi#208 (Documents the problem, which is the best we can do.)
If the new behavior of Cursor's implementation seems more inconvenient for actual usage, I am happy to review another PR to adjust such implementation details. Unspecified is unspecified, after all. But if we do so then we should at least internally document our apparent preference. ( It also seems likely to me that Read has been implemented "both ways" by various types in the ecosystem, so this definitely can't be expected to cut in a particular direction for Read in general. ) |
@workingjubilee I don't think I ran my test against a |
Thanks for the additional context! That's useful to know. |
I don't think this is a bug in
byteorder
. But I thought it demonstrates an interesting hazard that might be worth documenting for others.Some
byteorder::ReadBytesExt
methods rely onstd::io::Read::read_exact
, which has a warning about the error case:This means that e.g.
byteorder::read_u16
has the same hazard: if it encounters the end of the reader, the reader is now in an unspecified state.So code like this is wrong:
I recently stumbled over code that did exactly this, because the standard library changed its (unspecified) behavior. In older versions, the function above behaved as expected (remainder bytes stayed in the reader after the error). In rust 1.80.0, the remainder bytes are consumed. The following unit test demonstrates (comment out the assert for your version):
The
byteorder::ReadBytesExt
methods are documented to track theread_exact
error behavior:But maybe more should be done? I'm not sure how often this pattern might exist in the wild. Maybe the docs should be extended to warn people that the input stream can't be relied on after an error is returned?
The text was updated successfully, but these errors were encountered: