In this case, this is indeed undefined behavior, since Rio converts the buffer to libc::iovec, which is basically a "pointer + length", and writes through that pointer (required for read_at) are, indeed, undefined behavior.
The problem is that read_at expects &impl AsIoVecMut, whereas it should really expect either &mut impl AsIoVecMut or just impl AsIoVecMut directly. This trait is implemented wherever AsMut<u8> is implemented, so &Vec<u8> would be out of question.
Not sure, since the problem is not just here - it's in the fact that AsIoVecMut doesn't provide the method which goes through &mut self, i.e., even if we use &mut B, Rio will internally convert via the &B.
Put another way, are you saying something like this:
Look at:
pub trait AsIoVec {
/// Returns the address of this object.
fn into_new_iovec(&self) -> libc::iovec;
}
part of the problem here is that in C land libc::iovec can be used for both read and write. In Rust land, since this is coming from a &self and not a &mut self, this libc::iovec should only be used for reading.
So, a necessary, but possibly insufficient starting point is we should have
pub struct IOVec_ReadOnly(libc::iovec)
pub struct IOVec_ReadWrite(libc::iovec)
pub trait AsIoVec {
/// Returns the address of this object.
fn into_new_iovec(&self) -> IOVec_ReadOnly,
}
pub trait AsIoMutVec {
/// Returns the address of this object.
fn into_new_iovec(&mut self) -> IOVec_ReadWrite,
}
then, in the C ffi calls, the IOVec_ReadOnly should only be used for reading, while the IoVec_ReadWrite can be used for both read and write.
Yes, that's what I'm talking about. It's possible to use the same type for both read and write, as long as it can be proven that iovec used for writing was created from exclusive reference, but this is indeed less safe (i.e. provides less compile-time verification) then your idea.