Skip to content

Confusing documentation on mem::transmute #64073

Closed
@Shnatsel

Description

@Shnatsel

Documentation on mem::transmute presents the following piece of code:

let store = [0, 1, 2, 3];
let mut v_orig = store.iter().collect::<Vec<&i32>>();

// Using transmute: this is Undefined Behavior, and a bad idea.
// However, it is no-copy.
let v_transmuted = unsafe {
    std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
        v_orig.clone())
};

// This is the suggested, safe way.
// It does copy the entire vector, though, into a new array.
let v_collected = v_orig.clone()
                        .into_iter()
                        .map(|r| Some(r))
                        .collect::<Vec<Option<&i32>>>();

// The no-copy, unsafe way, still using transmute, but not UB.
// This is equivalent to the original, but safer, and reuses the
// same `Vec` internals. Therefore, the new inner type must have the
// exact same size, and the same alignment, as the old type.
// The same caveats exist for this method as transmute, for
// the original inner type (`&i32`) to the converted inner type
// (`Option<&i32>`), so read the nomicon pages linked above.
let v_from_raw = unsafe {
    Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
                        v_orig.len(),
                        v_orig.capacity())
};
std::mem::forget(v_orig);

The problem is it's never explained why the first described solution is Undefined Behavior. This is confusing.

Second, the use of transmute from &i32 to Option<&i32> which is inherently unsafe is not very illustrative. This is actually guaranteed to be safe, but that's not explicitly called out in the snippet. Perhaps transmuting NonZeroU8 to u8 or possibly char to u32 would be a better example.

Finally, the proposed "correct" way of doing this seems to actually contain undefined behavior: std::mem::forget(v_orig); is called only after the new vector is created, and until it's called there are two mutable references to the backing storage of v_orig.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-docsArea: Documentation for any part of the project, including the compiler, standard library, and tools

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions