-
Notifications
You must be signed in to change notification settings - Fork 290
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
Request: Provide try_get_* methods #254
Comments
I agree this would be helpful to have. If you look at the rust-fuzz trophy case, many of the bugs in the I think we need to answer a couple of questions, first.
|
That's what I would lean towards. Since the APIs here are just about reading, I don't see a need for more error variants. |
We use this pattern heavily in quinn and it works great. We even have an extension trait for all
I'm a fan of this approach, since it's overwhelmingly the way we use the |
After much bikeshedding in Discord, I'm leaning back towards providing The reasoning is, while it makes a lot of sense for It also doesn't feel great for |
I'm also a big fan "no-panic by default". IMO, out-of-bounds panicking is one of the biggest design mistakes in As far as I can tell, A First, it feels like it's a bit against Rust's design philosophy IMO? Currently most of Rust is like: "Ah nope, this is dangerous… You sure you wanna do this?", whereas an Also in this case, When it comes to the specific API, I'm in favor of returning an
|
As mentioned in discord, I think something like this could work pretty well: https://godbolt.org/z/hjYbeEf5P. We could also do a blanket impl: |
in the meantime, this might do what you're looking for - https://github.com/danieleades/safer-bytes |
i'm please to hear it might help. That inspired me to tidy it up a little |
Another implementation is use bytes::Buf;
use std::mem::size_of();
#[derive(Clone, Copy, Debug)]
pub enum ErrorKind {
EOF
}
pub trait TryBuf {
fn try_get_u8(&mut self) -> Result<u8,ErrorKind>;
// ...other try_get APIs
}
impl<T: Buf> TryBuf for T {
fn try_get_u8(&mut self) -> Result<u8,ErrorKind> {
if (size_of::<u8>() <= self.remaining()) {
Ok(self.get_u8())
} else {
Err(ErrorKind)
}
}
// ...other impls
} This is efficient and will never break any existing usage of I implement this in try_buf |
The issue with first checking that it is enough, and then reading, is that the reading part can very easily be changed by yourself or someone without updating the above check, causing a possible panic point. It is also quite error prone and unclear by hand calculating the size, E.g; having a literal In other words, panics become a surprise because some code changed further down, which goes against the general design of Rust of not upholding invariants yourself, E.g parse and not validate, or using types rather than checks to commicate impossibilites and guarantees. Furthermore, the manual method makes it very hard to validate if the size depends on data that has already been read, like branching code, which requires making each "section" do its own validating and manual calculation of what the code already knowns and encode. Similar in a way to hand calculating stack offsets based on function bodies, which we all know how well that goes as son as there is a branch. Though this is just my take on the matter when writing networking code and attempting to uphold and remember implicit assumptions as functions may panic otherwise with no clear indication that they will based on signature. |
Hello, It's worked a treat, thanks 👍 Happy to help with this where I can |
I think this is really needed. If you're decoding a non-trivial protocol that takes untrusted input, then it will be far superior to today's API. The type system will in effect end up enforcing safe and correct behaviour, while today's API is error prone and can lead to code that panics on bad input. You will perhaps loose a little speed, but on the other hand modern optimizing compilers are amazing at removing unnecessary checks, so this might not actually be the case. This issue has been open for some time. If I just went ahead and wrote a "TryBuf" as a blanket implementation for Buf, what are the chances that such a PR would get accepted? |
I missed the open PR on this. Is there any chance of that getting merged? It looks like just what many of us have wished for. It looks complete at first glance (with the possible exception of tests), but I'll be happy to help out if needed. |
Some network protocols have dynamic length packets, so we can not have a single
buf.remaining()
check before starting parsing them. In that case beforeget_*
we need to check the remaining length to avoid assertions.I believe
try_get_*
methods that do not assert they will help us write cleaner code.The text was updated successfully, but these errors were encountered: