Skip to content

transmute &[T] to &[U] may cause truncations for whole bit-pattern when size_of::<T> > size_of::<U> #10286

@KisaragiEffective

Description

@KisaragiEffective

What it does

Consider following example:

let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321];
let b: &[u8] = unsafe { std::mem::transmute(a) };

assert_eq!(b[0], 0x78);
assert_eq!(b[1], 0xEF);
assert_eq!(b[2], 0x09);
assert_eq!(b[3], 0x21);

but this is not true. This may be true (depending on architecture):

assert_eq!(b[0], 0x12);
assert_eq!(b[1], 0x34);
assert_eq!(b[2], 0x56);
assert_eq!(b[3], 0x78);

or this:

assert_eq!(b[0], 0x78);
assert_eq!(b[1], 0x56);
assert_eq!(b[2], 0x34);
assert_eq!(b[3], 0x12);

This is generic over both element type (in above example, u32 and u8).

This can be rewritten as:

// reinterpret bit-pattern of *each element*
let b: &[u8] = a.iter()
    .map(|it| unsafe { std::mem::transmute(it) })
    .collect::<Vec<_>>()
    .collect();

or

// reinterpret whole bit-pattern
let (prefix, align_result, suffix) = original_slice.align_to::<u8>();
assert_eq!(prefix.len(), 0);
assert_eq!(suffix.len(), 0);

Lint Name

transmute_to_smaller_element_may_cause_truncation

Category

suspicious

Advantage

  • Prevents truncations for whole bit-pattern.

Drawbacks

  • None

Example

let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321];
let b: &[u8] = unsafe { std::mem::transmute(a) };

Could be written as:

// reinterpret bit-pattern of *each element*
let b: &[u8] = a.iter()
    .map(|it| unsafe { std::mem::transmute(it) })
    .collect::<Vec<_>>()
    .collect();

or

// reinterpret whole bit-pattern
let (prefix, b, suffix) = original_slice.align_to::<u8>();
assert_eq!(prefix.len(), 0);
assert_eq!(suffix.len(), 0);

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintArea: New lints

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions