google / google/zerocopy

Support DST pointer casts in `const fn`

Open
#1,967 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
2.6k
Forks
179
Avg merge
1d 19h
Merged PRs (30d)
29

Description

The following is not valid:

```rust
fn cast(t: *mut T) -> *mut U {
t as *mut U
}
```

Rust isn't able to guarantee that `T` and `U` have the same "vtable kinds", and thus isn't able to prove that `*mut T` and `*mut U` have compatible pointer metadata. We currently work around this using this method on `KnownLayout`:

https://github.com/google/zerocopy/blob/0fae530a5b2e0566064548ed59f4918d424fd01b/src/lib.rs#L731

This has a limitation: It can't be called in a `const` context.

Instead, we could make casting unsafe, requiring the caller to promise to ensure that the pointers are either both thin or both fat, and use a union-transmute under the hood to avoid the vtable problem:

```rust
/// # Safety
///
/// The caller must ensure that `Src` and `Dst` must either both be `Sized` or
/// both be unsized.
const unsafe fn cast_unchecked(src: *mut Src) -> *mut Dst {
#[repr(C)]
union Transmute {
src: Src,
dst: Dst,
}

unsafe { Transmute { src }.dst }
}
```

The behavior of this union-transmute is *almost* well-defined, but not quite. The Reference [guarantees the behavior of raw pointer casts](https://doc.rust-lang.org/1.82.0/reference/expressions/operator-expr.html#pointer-to-pointer-cast), but makes no guarantee that the equivalent transmute has the same behavior as a cast. I've put up a PR to guarantee that this is well-defined: https://github.com/rust-lang/reference/pull/1661

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.