Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transmuting u8 buffer to struct in Rust

I have a byte buffer of unknown size, and I want to create a local struct variable pointing to the memory of the beginning of the buffer. Following what I'd do in C, I tried a lot of different things in Rust and kept getting errors. This is my latest attempt:

use std::mem::{size_of, transmute};

#[repr(C, packed)]
struct MyStruct {
    foo: u16,
    bar: u8,
}

fn main() {
    let v: Vec<u8> = vec![1, 2, 3];
    let buffer = v.as_slice();
    let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
}

I get an error:

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> src/main.rs:12:42
    |
12  |     let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
like image 510
sudo Avatar asked Feb 28 '17 02:02

sudo


People also ask

What is the use of transmute in rust?

There are a few things that transmute is really useful for. Turning a pointer into a function pointer. This is not portable to machines where function pointers and data pointers have different sizes. Extending a lifetime, or shortening an invariant lifetime. This is advanced, very unsafe Rust!

Is it safe to use [U8] as the output of a function?

Otherwise the function is fairly safe since it prevents buffer over-run since the output is read-only, fixed number of bytes, and its lifetime is bound to the input. If you wanted a version that returned a &mut [u8], that would be quite dangerous since modifying could easily create inconsistent/corrupt data.

How do you turn a&STR into a U8?

Turning an &str into an & [u8]: Turning a Vec<&T> into a Vec<Option<&T>>. To transmute the inner type of the contents of a container, you must make sure to not violate any of the container’s invariants. For Vec, this means that both the size and alignment of the inner types have to match.

What is Buffer Buffer in C++?

buffer provides safe, write-only and generics-free byte buffers that can be used without initializing them first. The main trait of this library is Buffer that represents a type that can contain uninitialized bytes (such as Vec, ArrayVec, etc.) and can safely be read into (e.g. using ReadBuffer ).


1 Answers

If you don't want to copy the data to the struct but instead leave it in place, you can use slice::align_to. This creates a &MyStruct instead:

#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct MyStruct {
    foo: u16,
    bar: u8,
}

fn main() {
    let v = vec![1u8, 2, 3];

    // I copied this code from Stack Overflow
    // without understanding why this case is safe.
    let (head, body, _tail) = unsafe { v.align_to::<MyStruct>() };
    assert!(head.is_empty(), "Data was not aligned");
    let my_struct = &body[0];

    println!("{:?}", my_struct);
}

Here, it's safe to use align_to to transmute some bytes to MyStruct because we've used repr(C, packed) and all of the types in MyStruct can be any arbitrary bytes.

See also:

  • How to read a struct from a file in Rust?
  • Can I take a byte array and deserialize it into a struct?
like image 178
Shepmaster Avatar answered Sep 21 '22 10:09

Shepmaster