Skip to content
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

Not safe: Performs unaligned memory accesses #35

Closed
RalfJung opened this issue Nov 24, 2018 · 3 comments
Closed

Not safe: Performs unaligned memory accesses #35

RalfJung opened this issue Nov 24, 2018 · 3 comments
Labels

Comments

@RalfJung
Copy link

The following code:

extern crate safe_transmute;

fn main() {
    let bytes: &[u8] = &[0, 1, 2, 3, 4, 5];
    println!("{}", safe_transmute::guarded_transmute_pod::<u32>(bytes).unwrap());
    println!("{}", safe_transmute::guarded_transmute_pod::<u32>(&bytes[1..]).unwrap());
}

Creates an unaligned reference, and, worse, accesses memory through it. Both of these (even just the creation!) are undefined behavior. In other words, this crate exports functions safe that are not safe to use.

Generally, the entire safe API of this crate seems to be built ignoring alignment constraints. I am afraid that's not safe.

FWIW, miri finds this error and shows

error[E0080]: constant evaluation error: type validation failed: encountered unaligned reference
    --> /home/r/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/slice/mod.rs:4789:5
     |
4789 |     Repr { raw: FatPtr { data, len } }.rust
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference
     |
     = note: inside call to `std::slice::from_raw_parts::<u32>` at /home/r/.cargo/registry/src/github.com-1ecc6299db9ec823/safe-transmute-0.10.0/src/lib.rs:151:8
     = note: inside call to `safe_transmute::guarded_transmute::<u32>` at /home/r/.cargo/registry/src/github.com-1ecc6299db9ec823/safe-transmute-0.10.0/src/pod.rs:100:14
note: inside call to `safe_transmute::guarded_transmute_pod::<u32>` at src/main.rs:5:20
    --> src/main.rs:5:20
     |
5    |     println!("{}", safe_transmute::guarded_transmute_pod::<u32>(bytes).unwrap());
     |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@Enet4
Copy link
Collaborator

Enet4 commented Nov 24, 2018

Thank you for your insights, @RalfJung, they are much appreciated! This concern has been pointed out in #22 (which probably shouldn't have been closed).

While we understand that these methods are prone to unaligned memory access, we noticed that this doesn't affect general usage, and we are still thinking of ways to make the conversion safer while retaining efficiency. We left a notice in the documentation, but I understand that this isn't ideal.

@nabijaczleweli Personally, I wouldn't mind marking the affected functions as unsafe, or add alignment checks in these functions, for the time being. There will be a time when we cannot control how the community is going to use this library.

@RalfJung
Copy link
Author

Generally, the expectation in Rust is that if your function is not marked unsafe, then any way of using it is correct -- in the sense of not causing UB. That is the entire point of the safe-unsafe distinction, and it is crucial to Rust's promise of safe systems programming.

You could, in principle, check for alignment at run-time, before creating a reference. Alternatively, if you don't want your users to have to worry about alignment, you could use raw pointers and read_unaligned. I think at least for this particular function (guarded_transmute_pod), read_unaligned would actually be a good match.

@Enet4
Copy link
Collaborator

Enet4 commented Nov 24, 2018

I feel that the former leaves more room for efficient implementations, by thinking a priori. In particular, We can't make Vec to Vec conversions always work unless we copy memory or wrap the original buffer in some kind of UnalignedVec with a more restrictive API. On the other hand, if we provide facilities to create aligned slices and vectors, we can make this API safe without making it overly complicated. This of course, is my current opinion, and does not discard the possibility of having both ideas or the other one in this crate.

This will also make #9 harder to solve, but we ought to address safety first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants