-
Notifications
You must be signed in to change notification settings - Fork 98
refactor: Remove dyn Any usage in BufferElem #1672
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
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Jens Reidel <[email protected]>
Seems like this depends on #1671, I didn't compile check it when splitting up my branch. |
where | ||
T: Any, | ||
{ | ||
pub fn pop_front_deserialize<T>(&mut self) -> Option<Box<T, DeviceAlloc>> { |
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 we are giving up some type safety here. As long as the alignment matches, we can cast any buffer into a box of any type (or a vector in the case of pop_front_vec
), right?
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 didn't really have any "type safety" before. The behaviour change is that previously, it was e.g. possible to have [BufferElem::Sized, BufferElem::Vector]
(pseudo-code) and then calling pop_front_vector
would return None
, while now it won't complain and instead happily return you a Vec<u8>
. That isn't necessarily wrong and all conversions here are safe. Deserializing into the required type by the caller is left to the caller, we only ensure that the deserialization is sound.
If you had the order wrong before, e.g. receive_packet
would return None
, which is arguably wrong since it would not really detect that there was an issue in the code. Now, it lets you treat the buffers as what they are (buffers), and you cannot really "mishandle" it.
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.
Previously, the downcasting operation would check the variant (and the type ID in the case of the Sized
variant) of the box during downcasting and would error if a dynamic box of incorrect type was provided (The vectors are a special case as Rust did not [and probably still does not] allow us to handle Box<[u8]>
s as Box<dyn Any>
).
I think it is better to catch early when we are using a buffer of incorrect type. For example, we could forget to pop the header of a read operation and try to pop a vector from it directly. Currently, this will result in an error as the read buffer should be of the Vector
variant but the first buffer is BufferElement::Sized
. With the proposed changes, a vector also containing the VIRTIO header will be returned. If that buffer is passed on to the network stack, for example, the error will happen there as what should only be the frame will contain the VIRTIO header content that is not expected and cannot be handled by the network stack. Errors in the networking stack are particularly annoying as transmission errors are expected and result in repeated attempts instead of outright errors.
Another scenario would be the queue returning the incorrect transfer to the caller because of a buffer ID mix-up. The type ID check can allow us to catch early when we are given the result of an open operation, for example, when we were expecting a write result. Because the header type IDs are different, the downcast would return None
.
Of course, such hypotheticals depend on us making mistakes in our code but we do make mistakes and early error catching precautions make debugging much easier.
T: IntoBytes + Immutable, | ||
{ | ||
fn from(value: T) -> Self { | ||
Self(value.as_bytes().to_vec_in(DeviceAlloc)) |
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.
This introduces a copy that we were previously able to avoid.
Is there a particular reason why we want to get rid of the |
My motivation for this is twofold. First, a |
This gets rid of the
Box<dyn Any>
inBufferElem
and makes it a thin wrapper aroundVec<u8>
.