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

deny transmute of &[T] into &[U] where U is larger than T #10285

Closed
KisaragiEffective opened this issue Feb 4, 2023 · 1 comment · Fixed by #11849
Closed

deny transmute of &[T] into &[U] where U is larger than T #10285

KisaragiEffective opened this issue Feb 4, 2023 · 1 comment · Fixed by #11849
Assignees
Labels
A-lint Area: New lints

Comments

@KisaragiEffective
Copy link
Contributor

KisaragiEffective commented Feb 4, 2023

What it does

This prevents a kind of UB.

Examples:

let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8];
let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) };
// expected to be expanded
assert_eq!(alt_slice[0], 1);
assert_eq!(alt_slice[1], 2);
assert_eq!(alt_slice[2], 3);
assert_eq!(alt_slice[3], 4);

This is not true. alt_slice[0] have (mostly) 0x01020304 or 0x04030201 depending on byte-order, and left is looks like garbage and user thinks it is not what (s)he wanted.

Also, this contains UB. Miri reports call to transmute is UB.

I believe: mem::transmute::<&[T], &[U]> is UB if and only if mem::size_of<T> < mem::size_of<U>.

Alternatives:

This may not be MachineApplicable, because:
If user is expected to keep length and transmute each element:

// let original_slice: &[T] = ...
let alt_slice: &[U] = original_slice
    .iter()
    .map(|original| unsafe { core::mem::transmute(original) })
    .collect::<Vec<_>>()
    .as_slice()

If user is expected to transmute entire bit pattern of pointing bit-pattern:

// let original_slice: &[T] = ...
let (prefix, align_result, suffix) = original_slice.align_to::<U>();
assert_eq!(prefix.len(), 0);
assert_eq!(suffix.len(), 0);

Lint Name

transmute_to_larger_element_slice

Category

correctness

Advantage

  • Prevents a kind of UB.

Drawbacks

No response

Example

// let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8];
let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) };

Could be written as:

let alt_slice: &[u32] = original_slice
    .iter()
    .map(|original| unsafe { core::mem::transmute(original) })
    .collect::<Vec<_>>()
    .as_slice()

or

let (prefix, align_result, suffix) = original_slice.align_to::<u32>();
assert_eq!(prefix.len(), 0);
assert_eq!(suffix.len(), 0);
@KisaragiEffective
Copy link
Contributor Author

@rustbot claim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints
Projects
None yet
1 participant