Can read() overflow a buffer?

Nope. Safe methods of unsafe trait are subject to all the usual rules.

The difference between safe and unsafe traits is whether the fact that trait is implemented conveys more information that is encoded in the type system. For example, Send and Sync are both unsafe, and by implementing it we assert to the compiler that the type is safe to move or share between threads, respectively. Read, on the other side, isn't unsafe - therefore, the only things that are guaranteed are, essentially, the method signatures; everything else is an expectation, but it must not be treated as guarantee.

1 Like

It boils down to what sorts of problems can happen if the trait implementation is buggy. Rust's rule of thumb is that all unsoundness is caused by unsafe code, and that outside of unsafe code, bugs must never be able to cause undefined behaviour.

Thus, if you're writing unsafe code, interacting with Read::read, and n > buf.len(), you can generate an error, or return nonsense values. You can't overflow the buffer, or read out of bounds as a result - it's on you to ensure that the return value is in-bounds.

So, as an example, if I write:

let data = vec![0;256];
let bytes_read = input.read(&mut data)?;

unsafe {
    data.get_unchecked(bytes_read / 2)
}

I've done something wrong - if input's implementation of read is buggy, then I could attempt an out-of-bounds read (e.g. if bytes_read was 1024), and the documentation is making it clear that the consequences of that out-of-bound read are my fault.

On the other hand, if I write:

let data = vec![0;256];
let bytes_read = input.read(&mut data)?;

data.get(bytes_read / 2).expect("bytes_read was out of bounds")

I'm no longer going to attempt an out-of-bounds read (because I'm using the checked variant of get), and thus I'm OK.

If I wanted to, I could also write:

let data = vec![0;256];
let bytes_read = input.read(&mut data)?;

unsafe {
    data.get_unchecked((data.len() / 2).min(bytes_read / 2))
}

This is also fine, because I ensure that the value is in-bounds before doing my read, but might still return nonsense (because the input.read implementation was buggy).

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.