diff mbox series

[v7,7/7] rust: enable `clippy::ref_as_ptr` lint

Message ID 20250325-ptr-as-ptr-v7-7-87ab452147b9@gmail.com (mailing list archive)
State New
Headers show
Series rust: reduce `as` casts, enable related lints | expand

Commit Message

Tamir Duberstein March 25, 2025, 8:07 p.m. UTC
In Rust 1.78.0, Clippy introduced the `ref_as_ptr` lint [1]:

> Using `as` casts may result in silently changing mutability or type.

While this doesn't eliminate unchecked `as` conversions, it makes such
conversions easier to scrutinize.  It also has the slight benefit of
removing a degree of freedom on which to bikeshed. Thus apply the
changes and enable the lint -- no functional change intended.

Link: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr [1]
Suggested-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/all/D8PGG7NTWB6U.3SS3A5LN4XWMN@proton.me/
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
 Makefile                 | 1 +
 rust/bindings/lib.rs     | 1 +
 rust/kernel/device_id.rs | 3 ++-
 rust/kernel/fs/file.rs   | 3 ++-
 rust/kernel/str.rs       | 4 ++--
 rust/kernel/uaccess.rs   | 5 +++--
 rust/uapi/lib.rs         | 1 +
 7 files changed, 12 insertions(+), 6 deletions(-)

Comments

Benno Lossin March 25, 2025, 10:11 p.m. UTC | #1
On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
> diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> index 40034f77fc2f..6233af50bab7 100644
> --- a/rust/kernel/str.rs
> +++ b/rust/kernel/str.rs
> @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
>      #[inline]
>      pub const fn from_bytes(bytes: &[u8]) -> &Self {
>          // SAFETY: `BStr` is transparent to `[u8]`.
> -        unsafe { &*(bytes as *const [u8] as *const BStr) }
> +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }

Hmm I'm not sure about using `transmute` here. Yes the types are
transparent, but I don't think that we should use it here.

>      }
>  
>      /// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
> @@ -290,7 +290,7 @@ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError
>      #[inline]
>      pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
>          // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
> -        unsafe { &mut *(bytes as *mut [u8] as *mut CStr) }
> +        unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut Self>(bytes)) }
>      }
>  
>      /// Returns a C pointer to the string.
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index 80a9782b1c6e..c042b1fe499e 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -242,7 +242,7 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit<u8>]) -> Result {
>      pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
>          // SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to
>          // `out`.
> -        let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) };
> +        let out = unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut [MaybeUninit<u8>]>(out)) };

I have a patch that adds a `cast_slice_mut` method that could be used
here, so I can fix it in that series. But let's not use `transmute` here
either.

---
Cheers,
Benno

>          self.read_raw(out)
>      }
>
Tamir Duberstein March 25, 2025, 10:33 p.m. UTC | #2
On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> > index 40034f77fc2f..6233af50bab7 100644
> > --- a/rust/kernel/str.rs
> > +++ b/rust/kernel/str.rs
> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
> >      #[inline]
> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
> >          // SAFETY: `BStr` is transparent to `[u8]`.
> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
>
> Hmm I'm not sure about using `transmute` here. Yes the types are
> transparent, but I don't think that we should use it here.

What's your suggestion? I initially tried

let bytes: *const [u8] = bytes;
unsafe { &*bytes.cast() }

but that doesn't compile because of the implicit Sized bound on pointer::cast.

>
> >      }
> >
> >      /// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
> > @@ -290,7 +290,7 @@ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError
> >      #[inline]
> >      pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
> >          // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
> > -        unsafe { &mut *(bytes as *mut [u8] as *mut CStr) }
> > +        unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut Self>(bytes)) }
> >      }
> >
> >      /// Returns a C pointer to the string.
> > diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> > index 80a9782b1c6e..c042b1fe499e 100644
> > --- a/rust/kernel/uaccess.rs
> > +++ b/rust/kernel/uaccess.rs
> > @@ -242,7 +242,7 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit<u8>]) -> Result {
> >      pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
> >          // SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to
> >          // `out`.
> > -        let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) };
> > +        let out = unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut [MaybeUninit<u8>]>(out)) };
>
> I have a patch that adds a `cast_slice_mut` method that could be used
> here, so I can fix it in that series. But let's not use `transmute` here
> either.

See above - I don't know what else I could write here.
Benno Lossin March 25, 2025, 10:40 p.m. UTC | #3
On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
> On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
>>
>> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
>> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
>> > index 40034f77fc2f..6233af50bab7 100644
>> > --- a/rust/kernel/str.rs
>> > +++ b/rust/kernel/str.rs
>> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
>> >      #[inline]
>> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
>> >          // SAFETY: `BStr` is transparent to `[u8]`.
>> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
>> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
>>
>> Hmm I'm not sure about using `transmute` here. Yes the types are
>> transparent, but I don't think that we should use it here.
>
> What's your suggestion? I initially tried
>
> let bytes: *const [u8] = bytes;
> unsafe { &*bytes.cast() }
>
> but that doesn't compile because of the implicit Sized bound on pointer::cast.

This is AFAIK one of the only places where we cannot get rid of the `as`
cast. So:

    let bytes: *const [u8] = bytes;
    // CAST: `BStr` transparently wraps `[u8]`.
    let bytes = bytes as *const BStr;
    // SAFETY: `bytes` is derived from a reference.
    unsafe { &*bytes }

IMO a `transmute` is worse than an `as` cast :)

---
Cheers,
Benno
Tamir Duberstein March 25, 2025, 11:54 p.m. UTC | #4
On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >>
> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> >> > index 40034f77fc2f..6233af50bab7 100644
> >> > --- a/rust/kernel/str.rs
> >> > +++ b/rust/kernel/str.rs
> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
> >> >      #[inline]
> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
> >>
> >> Hmm I'm not sure about using `transmute` here. Yes the types are
> >> transparent, but I don't think that we should use it here.
> >
> > What's your suggestion? I initially tried
> >
> > let bytes: *const [u8] = bytes;
> > unsafe { &*bytes.cast() }
> >
> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
>
> This is AFAIK one of the only places where we cannot get rid of the `as`
> cast. So:
>
>     let bytes: *const [u8] = bytes;
>     // CAST: `BStr` transparently wraps `[u8]`.
>     let bytes = bytes as *const BStr;
>     // SAFETY: `bytes` is derived from a reference.
>     unsafe { &*bytes }
>
> IMO a `transmute` is worse than an `as` cast :)

Hmm, looking at this again we can just transmute ref-to-ref and avoid
pointers entirely. We're already doing that in
`CStr::from_bytes_with_nul_unchecked`

Why is transmute worse than an `as` cast?
Benno Lossin March 26, 2025, 10:30 a.m. UTC | #5
On Wed Mar 26, 2025 at 12:54 AM CET, Tamir Duberstein wrote:
> On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
>> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
>> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
>> >> > index 40034f77fc2f..6233af50bab7 100644
>> >> > --- a/rust/kernel/str.rs
>> >> > +++ b/rust/kernel/str.rs
>> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
>> >> >      #[inline]
>> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
>> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
>> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
>> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
>> >>
>> >> Hmm I'm not sure about using `transmute` here. Yes the types are
>> >> transparent, but I don't think that we should use it here.
>> >
>> > What's your suggestion? I initially tried
>> >
>> > let bytes: *const [u8] = bytes;
>> > unsafe { &*bytes.cast() }
>> >
>> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
>>
>> This is AFAIK one of the only places where we cannot get rid of the `as`
>> cast. So:
>>
>>     let bytes: *const [u8] = bytes;
>>     // CAST: `BStr` transparently wraps `[u8]`.
>>     let bytes = bytes as *const BStr;
>>     // SAFETY: `bytes` is derived from a reference.
>>     unsafe { &*bytes }
>>
>> IMO a `transmute` is worse than an `as` cast :)
>
> Hmm, looking at this again we can just transmute ref-to-ref and avoid
> pointers entirely. We're already doing that in
> `CStr::from_bytes_with_nul_unchecked`
>
> Why is transmute worse than an `as` cast?

It's right in the docs: "`transmute` should be the absolute last
resort." [1]. IIRC, Gary was a bit more lenient in its use, but I think
we should avoid it as much as possible such that people copying code or
taking inspiration also don't use it.

So for both cases I'd prefer an `as` cast.

[1]: https://doc.rust-lang.org/std/mem/fn.transmute.html

---
Cheers,
Benno
Tamir Duberstein March 26, 2025, 10:35 a.m. UTC | #6
On Wed, Mar 26, 2025 at 6:31 AM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Wed Mar 26, 2025 at 12:54 AM CET, Tamir Duberstein wrote:
> > On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
> >> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
> >> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> >> >> > index 40034f77fc2f..6233af50bab7 100644
> >> >> > --- a/rust/kernel/str.rs
> >> >> > +++ b/rust/kernel/str.rs
> >> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
> >> >> >      #[inline]
> >> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
> >> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
> >> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
> >> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
> >> >>
> >> >> Hmm I'm not sure about using `transmute` here. Yes the types are
> >> >> transparent, but I don't think that we should use it here.
> >> >
> >> > What's your suggestion? I initially tried
> >> >
> >> > let bytes: *const [u8] = bytes;
> >> > unsafe { &*bytes.cast() }
> >> >
> >> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
> >>
> >> This is AFAIK one of the only places where we cannot get rid of the `as`
> >> cast. So:
> >>
> >>     let bytes: *const [u8] = bytes;
> >>     // CAST: `BStr` transparently wraps `[u8]`.
> >>     let bytes = bytes as *const BStr;
> >>     // SAFETY: `bytes` is derived from a reference.
> >>     unsafe { &*bytes }
> >>
> >> IMO a `transmute` is worse than an `as` cast :)
> >
> > Hmm, looking at this again we can just transmute ref-to-ref and avoid
> > pointers entirely. We're already doing that in
> > `CStr::from_bytes_with_nul_unchecked`
> >
> > Why is transmute worse than an `as` cast?
>
> It's right in the docs: "`transmute` should be the absolute last
> resort." [1]. IIRC, Gary was a bit more lenient in its use, but I think
> we should avoid it as much as possible such that people copying code or
> taking inspiration also don't use it.
>
> So for both cases I'd prefer an `as` cast.
>
> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html

I don't follow the logic. The trouble with `as` casts is that they are
very lenient in what they allow, and to do these conversions with `as`
casts requires ref -> pointer -> pointer -> pointer deref versus a
single transmute. The safety comment perfectly describes why it's OK
to do: the types are transparent. So why is `as` casting pointers
better? It's just as unchecked as transmuting, and worse, it requires
a raw pointer dereference.
Benno Lossin March 26, 2025, 4:43 p.m. UTC | #7
On Wed Mar 26, 2025 at 11:35 AM CET, Tamir Duberstein wrote:
> On Wed, Mar 26, 2025 at 6:31 AM Benno Lossin <benno.lossin@proton.me> wrote:
>> On Wed Mar 26, 2025 at 12:54 AM CET, Tamir Duberstein wrote:
>> > On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
>> >> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
>> >> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
>> >> >> > index 40034f77fc2f..6233af50bab7 100644
>> >> >> > --- a/rust/kernel/str.rs
>> >> >> > +++ b/rust/kernel/str.rs
>> >> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
>> >> >> >      #[inline]
>> >> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
>> >> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
>> >> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
>> >> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
>> >> >>
>> >> >> Hmm I'm not sure about using `transmute` here. Yes the types are
>> >> >> transparent, but I don't think that we should use it here.
>> >> >
>> >> > What's your suggestion? I initially tried
>> >> >
>> >> > let bytes: *const [u8] = bytes;
>> >> > unsafe { &*bytes.cast() }
>> >> >
>> >> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
>> >>
>> >> This is AFAIK one of the only places where we cannot get rid of the `as`
>> >> cast. So:
>> >>
>> >>     let bytes: *const [u8] = bytes;
>> >>     // CAST: `BStr` transparently wraps `[u8]`.
>> >>     let bytes = bytes as *const BStr;
>> >>     // SAFETY: `bytes` is derived from a reference.
>> >>     unsafe { &*bytes }
>> >>
>> >> IMO a `transmute` is worse than an `as` cast :)
>> >
>> > Hmm, looking at this again we can just transmute ref-to-ref and avoid
>> > pointers entirely. We're already doing that in
>> > `CStr::from_bytes_with_nul_unchecked`
>> >
>> > Why is transmute worse than an `as` cast?
>>
>> It's right in the docs: "`transmute` should be the absolute last
>> resort." [1]. IIRC, Gary was a bit more lenient in its use, but I think
>> we should avoid it as much as possible such that people copying code or
>> taking inspiration also don't use it.
>>
>> So for both cases I'd prefer an `as` cast.
>>
>> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html
>
> I don't follow the logic. The trouble with `as` casts is that they are
> very lenient in what they allow, and to do these conversions with `as`
> casts requires ref -> pointer -> pointer -> pointer deref versus a
> single transmute. The safety comment perfectly describes why it's OK
> to do: the types are transparent. So why is `as` casting pointers
> better? It's just as unchecked as transmuting, and worse, it requires
> a raw pointer dereference.

Note that you're not transmuting `[u8]` to `BStr`, but `*const [u8]` to
`*const BStr`. Those pointers have provenance and I'm not sure if
transmuting them preserves it.

I tried to find some existing issues about the topic and found that
there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
asking for a better justification [1] and it seems like nobody provided
one there. Maybe we should ask the opsem team what happens to provenance
when transmuting?

[1]: https://github.com/rust-lang/rust-clippy/issues/6372

---
Cheers,
Benno
Tamir Duberstein March 26, 2025, 4:57 p.m. UTC | #8
On Wed, Mar 26, 2025 at 12:43 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Wed Mar 26, 2025 at 11:35 AM CET, Tamir Duberstein wrote:
> > On Wed, Mar 26, 2025 at 6:31 AM Benno Lossin <benno.lossin@proton.me> wrote:
> >> On Wed Mar 26, 2025 at 12:54 AM CET, Tamir Duberstein wrote:
> >> > On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> >> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
> >> >> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> >> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
> >> >> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> >> >> >> > index 40034f77fc2f..6233af50bab7 100644
> >> >> >> > --- a/rust/kernel/str.rs
> >> >> >> > +++ b/rust/kernel/str.rs
> >> >> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
> >> >> >> >      #[inline]
> >> >> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
> >> >> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
> >> >> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
> >> >> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
> >> >> >>
> >> >> >> Hmm I'm not sure about using `transmute` here. Yes the types are
> >> >> >> transparent, but I don't think that we should use it here.
> >> >> >
> >> >> > What's your suggestion? I initially tried
> >> >> >
> >> >> > let bytes: *const [u8] = bytes;
> >> >> > unsafe { &*bytes.cast() }
> >> >> >
> >> >> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
> >> >>
> >> >> This is AFAIK one of the only places where we cannot get rid of the `as`
> >> >> cast. So:
> >> >>
> >> >>     let bytes: *const [u8] = bytes;
> >> >>     // CAST: `BStr` transparently wraps `[u8]`.
> >> >>     let bytes = bytes as *const BStr;
> >> >>     // SAFETY: `bytes` is derived from a reference.
> >> >>     unsafe { &*bytes }
> >> >>
> >> >> IMO a `transmute` is worse than an `as` cast :)
> >> >
> >> > Hmm, looking at this again we can just transmute ref-to-ref and avoid
> >> > pointers entirely. We're already doing that in
> >> > `CStr::from_bytes_with_nul_unchecked`
> >> >
> >> > Why is transmute worse than an `as` cast?
> >>
> >> It's right in the docs: "`transmute` should be the absolute last
> >> resort." [1]. IIRC, Gary was a bit more lenient in its use, but I think
> >> we should avoid it as much as possible such that people copying code or
> >> taking inspiration also don't use it.
> >>
> >> So for both cases I'd prefer an `as` cast.
> >>
> >> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html
> >
> > I don't follow the logic. The trouble with `as` casts is that they are
> > very lenient in what they allow, and to do these conversions with `as`
> > casts requires ref -> pointer -> pointer -> pointer deref versus a
> > single transmute. The safety comment perfectly describes why it's OK
> > to do: the types are transparent. So why is `as` casting pointers
> > better? It's just as unchecked as transmuting, and worse, it requires
> > a raw pointer dereference.
>
> Note that you're not transmuting `[u8]` to `BStr`, but `*const [u8]` to
> `*const BStr`. Those pointers have provenance and I'm not sure if
> transmuting them preserves it.

In the current code you're looking at, yes. But in the code I have
locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
said "Hmm, looking at this again we can just transmute ref-to-ref and
avoid pointers entirely. We're already doing that in
`CStr::from_bytes_with_nul_unchecked`".

> I tried to find some existing issues about the topic and found that
> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
> asking for a better justification [1] and it seems like nobody provided
> one there. Maybe we should ask the opsem team what happens to provenance
> when transmuting?

Yeah, we should do this - but again: not relevant in this discussion.
Benno Lossin March 26, 2025, 5:36 p.m. UTC | #9
On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> On Wed, Mar 26, 2025 at 12:43 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> On Wed Mar 26, 2025 at 11:35 AM CET, Tamir Duberstein wrote:
>> > On Wed, Mar 26, 2025 at 6:31 AM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> On Wed Mar 26, 2025 at 12:54 AM CET, Tamir Duberstein wrote:
>> >> > On Tue, Mar 25, 2025 at 6:40 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> >> On Tue Mar 25, 2025 at 11:33 PM CET, Tamir Duberstein wrote:
>> >> >> > On Tue, Mar 25, 2025 at 6:11 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> >> >> On Tue Mar 25, 2025 at 9:07 PM CET, Tamir Duberstein wrote:
>> >> >> >> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
>> >> >> >> > index 40034f77fc2f..6233af50bab7 100644
>> >> >> >> > --- a/rust/kernel/str.rs
>> >> >> >> > +++ b/rust/kernel/str.rs
>> >> >> >> > @@ -29,7 +29,7 @@ pub const fn is_empty(&self) -> bool {
>> >> >> >> >      #[inline]
>> >> >> >> >      pub const fn from_bytes(bytes: &[u8]) -> &Self {
>> >> >> >> >          // SAFETY: `BStr` is transparent to `[u8]`.
>> >> >> >> > -        unsafe { &*(bytes as *const [u8] as *const BStr) }
>> >> >> >> > +        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
>> >> >> >>
>> >> >> >> Hmm I'm not sure about using `transmute` here. Yes the types are
>> >> >> >> transparent, but I don't think that we should use it here.
>> >> >> >
>> >> >> > What's your suggestion? I initially tried
>> >> >> >
>> >> >> > let bytes: *const [u8] = bytes;
>> >> >> > unsafe { &*bytes.cast() }
>> >> >> >
>> >> >> > but that doesn't compile because of the implicit Sized bound on pointer::cast.
>> >> >>
>> >> >> This is AFAIK one of the only places where we cannot get rid of the `as`
>> >> >> cast. So:
>> >> >>
>> >> >>     let bytes: *const [u8] = bytes;
>> >> >>     // CAST: `BStr` transparently wraps `[u8]`.
>> >> >>     let bytes = bytes as *const BStr;
>> >> >>     // SAFETY: `bytes` is derived from a reference.
>> >> >>     unsafe { &*bytes }
>> >> >>
>> >> >> IMO a `transmute` is worse than an `as` cast :)
>> >> >
>> >> > Hmm, looking at this again we can just transmute ref-to-ref and avoid
>> >> > pointers entirely. We're already doing that in
>> >> > `CStr::from_bytes_with_nul_unchecked`
>> >> >
>> >> > Why is transmute worse than an `as` cast?
>> >>
>> >> It's right in the docs: "`transmute` should be the absolute last
>> >> resort." [1]. IIRC, Gary was a bit more lenient in its use, but I think
>> >> we should avoid it as much as possible such that people copying code or
>> >> taking inspiration also don't use it.
>> >>
>> >> So for both cases I'd prefer an `as` cast.
>> >>
>> >> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html
>> >
>> > I don't follow the logic. The trouble with `as` casts is that they are
>> > very lenient in what they allow, and to do these conversions with `as`
>> > casts requires ref -> pointer -> pointer -> pointer deref versus a
>> > single transmute. The safety comment perfectly describes why it's OK
>> > to do: the types are transparent. So why is `as` casting pointers
>> > better? It's just as unchecked as transmuting, and worse, it requires
>> > a raw pointer dereference.
>>
>> Note that you're not transmuting `[u8]` to `BStr`, but `*const [u8]` to
>> `*const BStr`. Those pointers have provenance and I'm not sure if
>> transmuting them preserves it.
>
> In the current code you're looking at, yes. But in the code I have
> locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
> said "Hmm, looking at this again we can just transmute ref-to-ref and
> avoid pointers entirely. We're already doing that in
> `CStr::from_bytes_with_nul_unchecked`".

`CStr::from_bytes_with_nul_unchecked` does the transmute with
references. That is a usage that the docs of `transmute` explicitly
recommend to change to an `as` cast [1].

No idea about provenance still.

[1]: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives

>> I tried to find some existing issues about the topic and found that
>> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
>> asking for a better justification [1] and it seems like nobody provided
>> one there. Maybe we should ask the opsem team what happens to provenance
>> when transmuting?
>
> Yeah, we should do this - but again: not relevant in this discussion.

I think it's pretty relevant.

---
Cheers,
Benno
Tamir Duberstein March 26, 2025, 7:06 p.m. UTC | #10
On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> >
> >
> > In the current code you're looking at, yes. But in the code I have
> > locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
> > said "Hmm, looking at this again we can just transmute ref-to-ref and
> > avoid pointers entirely. We're already doing that in
> > `CStr::from_bytes_with_nul_unchecked`".
>
> `CStr::from_bytes_with_nul_unchecked` does the transmute with
> references. That is a usage that the docs of `transmute` explicitly
> recommend to change to an `as` cast [1].

RIght. That guidance was written in 2016
(https://github.com/rust-lang/rust/pull/34609) and doesn't present any
rationale for `as` casts being preferred to transmute. I posted a
comment in the most relevant issue I could find:
https://github.com/rust-lang/rust/issues/34249#issuecomment-2755316610.

> No idea about provenance still.

Well that's not surprising, nobody was thinking about provenance in
2016. But I really don't think we should blindly follow the advice in
this case. It doesn't make an iota of sense to me - does it make sense
to you?

>
> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives
>
> >> I tried to find some existing issues about the topic and found that
> >> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
> >> asking for a better justification [1] and it seems like nobody provided
> >> one there. Maybe we should ask the opsem team what happens to provenance
> >> when transmuting?
> >
> > Yeah, we should do this - but again: not relevant in this discussion.
>
> I think it's pretty relevant.

It's not relevant because we're no longer talking about transmuting
pointer to pointer. The two options are:
1. transmute reference to reference.
2. coerce reference to pointer, `as` cast pointer to pointer (triggers
`ptr_as_ptr`), reborrow pointer to reference.

If anyone can help me understand why (2) is better than (1), I'd
certainly appreciate it.
Tamir Duberstein March 26, 2025, 8:47 p.m. UTC | #11
On Wed, Mar 26, 2025 at 3:06 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >
> > On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> > >
> > >
> > > In the current code you're looking at, yes. But in the code I have
> > > locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
> > > said "Hmm, looking at this again we can just transmute ref-to-ref and
> > > avoid pointers entirely. We're already doing that in
> > > `CStr::from_bytes_with_nul_unchecked`".
> >
> > `CStr::from_bytes_with_nul_unchecked` does the transmute with
> > references. That is a usage that the docs of `transmute` explicitly
> > recommend to change to an `as` cast [1].
>
> RIght. That guidance was written in 2016
> (https://github.com/rust-lang/rust/pull/34609) and doesn't present any
> rationale for `as` casts being preferred to transmute. I posted a
> comment in the most relevant issue I could find:
> https://github.com/rust-lang/rust/issues/34249#issuecomment-2755316610.
>
> > No idea about provenance still.
>
> Well that's not surprising, nobody was thinking about provenance in
> 2016. But I really don't think we should blindly follow the advice in
> this case. It doesn't make an iota of sense to me - does it make sense
> to you?
>
> >
> > [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives
> >
> > >> I tried to find some existing issues about the topic and found that
> > >> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
> > >> asking for a better justification [1] and it seems like nobody provided
> > >> one there. Maybe we should ask the opsem team what happens to provenance
> > >> when transmuting?
> > >
> > > Yeah, we should do this - but again: not relevant in this discussion.
> >
> > I think it's pretty relevant.
>
> It's not relevant because we're no longer talking about transmuting
> pointer to pointer. The two options are:
> 1. transmute reference to reference.
> 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
> `ptr_as_ptr`), reborrow pointer to reference.
>
> If anyone can help me understand why (2) is better than (1), I'd
> certainly appreciate it.

Turns out there's a tortured past even in the standard library. In
2017 someone replaces trasmutes with pointer casts:

https://github.com/rust-lang/rust/commit/2633b85ab2c89822d2c227fc9e81c6ec1c0ed9b6

In 2020 someone changes it back to transmute:

https://github.com/rust-lang/rust/pull/75157/files

See also https://github.com/rust-lang/rust/pull/34609#issuecomment-230559871
which makes my point better than I have, particularly this snippet:
"In addition, casting through raw pointers removes the check that both
types have the same size that transmute does provide.".
Benno Lossin March 26, 2025, 9:09 p.m. UTC | #12
On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
> On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
>> > In the current code you're looking at, yes. But in the code I have
>> > locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
>> > said "Hmm, looking at this again we can just transmute ref-to-ref and
>> > avoid pointers entirely. We're already doing that in
>> > `CStr::from_bytes_with_nul_unchecked`".
>>
>> `CStr::from_bytes_with_nul_unchecked` does the transmute with
>> references. That is a usage that the docs of `transmute` explicitly
>> recommend to change to an `as` cast [1].
>
> RIght. That guidance was written in 2016
> (https://github.com/rust-lang/rust/pull/34609) and doesn't present any
> rationale for `as` casts being preferred to transmute. I posted a
> comment in the most relevant issue I could find:
> https://github.com/rust-lang/rust/issues/34249#issuecomment-2755316610.

Not sure if that's the correct issue, maybe we should post one on the
UCG (unsafe code guidelines). But before that we probably should ask on
zulip...

>> No idea about provenance still.
>
> Well that's not surprising, nobody was thinking about provenance in
> 2016. But I really don't think we should blindly follow the advice in
> this case. It doesn't make an iota of sense to me - does it make sense
> to you?

For ptr-to-int transmutes, I know that they will probably remove
provenance, hence I am a bit cautious about using them for ptr-to-ptr or
ref-to-ref.

>> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives
>>
>> >> I tried to find some existing issues about the topic and found that
>> >> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
>> >> asking for a better justification [1] and it seems like nobody provided
>> >> one there. Maybe we should ask the opsem team what happens to provenance
>> >> when transmuting?
>> >
>> > Yeah, we should do this - but again: not relevant in this discussion.
>>
>> I think it's pretty relevant.
>
> It's not relevant because we're no longer talking about transmuting
> pointer to pointer. The two options are:
> 1. transmute reference to reference.
> 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
> `ptr_as_ptr`), reborrow pointer to reference.
>
> If anyone can help me understand why (2) is better than (1), I'd
> certainly appreciate it.

I am very confident that (2) is correct. With (1) I'm not sure (see
above), so that's why I mentioned it.

---
Cheers,
Benno
Tamir Duberstein March 26, 2025, 10:09 p.m. UTC | #13
On Wed, Mar 26, 2025 at 5:09 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
> > On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> >> > In the current code you're looking at, yes. But in the code I have
> >> > locally I'm transmuting `[u8]` to `BStr`. See my earlier reply where I
> >> > said "Hmm, looking at this again we can just transmute ref-to-ref and
> >> > avoid pointers entirely. We're already doing that in
> >> > `CStr::from_bytes_with_nul_unchecked`".
> >>
> >> `CStr::from_bytes_with_nul_unchecked` does the transmute with
> >> references. That is a usage that the docs of `transmute` explicitly
> >> recommend to change to an `as` cast [1].
> >
> > RIght. That guidance was written in 2016
> > (https://github.com/rust-lang/rust/pull/34609) and doesn't present any
> > rationale for `as` casts being preferred to transmute. I posted a
> > comment in the most relevant issue I could find:
> > https://github.com/rust-lang/rust/issues/34249#issuecomment-2755316610.
>
> Not sure if that's the correct issue, maybe we should post one on the
> UCG (unsafe code guidelines). But before that we probably should ask on
> zulip...
>
> >> No idea about provenance still.
> >
> > Well that's not surprising, nobody was thinking about provenance in
> > 2016. But I really don't think we should blindly follow the advice in
> > this case. It doesn't make an iota of sense to me - does it make sense
> > to you?
>
> For ptr-to-int transmutes, I know that they will probably remove
> provenance, hence I am a bit cautious about using them for ptr-to-ptr or
> ref-to-ref.
>
> >> [1]: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives
> >>
> >> >> I tried to find some existing issues about the topic and found that
> >> >> there exists a clippy lint `transmute_ptr_to_ptr`. There is an issue
> >> >> asking for a better justification [1] and it seems like nobody provided
> >> >> one there. Maybe we should ask the opsem team what happens to provenance
> >> >> when transmuting?
> >> >
> >> > Yeah, we should do this - but again: not relevant in this discussion.
> >>
> >> I think it's pretty relevant.
> >
> > It's not relevant because we're no longer talking about transmuting
> > pointer to pointer. The two options are:
> > 1. transmute reference to reference.
> > 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
> > `ptr_as_ptr`), reborrow pointer to reference.
> >
> > If anyone can help me understand why (2) is better than (1), I'd
> > certainly appreciate it.
>
> I am very confident that (2) is correct. With (1) I'm not sure (see
> above), so that's why I mentioned it.

Can you help me understand why you're confident about (2) but not (1)?
Benno Lossin March 26, 2025, 10:15 p.m. UTC | #14
On Wed Mar 26, 2025 at 11:09 PM CET, Tamir Duberstein wrote:
> On Wed, Mar 26, 2025 at 5:09 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
>> > On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> >> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
>> >> >
>> >> > Yeah, we should do this - but again: not relevant in this discussion.
>> >>
>> >> I think it's pretty relevant.
>> >
>> > It's not relevant because we're no longer talking about transmuting
>> > pointer to pointer. The two options are:
>> > 1. transmute reference to reference.
>> > 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
>> > `ptr_as_ptr`), reborrow pointer to reference.
>> >
>> > If anyone can help me understand why (2) is better than (1), I'd
>> > certainly appreciate it.
>>
>> I am very confident that (2) is correct. With (1) I'm not sure (see
>> above), so that's why I mentioned it.
>
> Can you help me understand why you're confident about (2) but not (1)?

My explanation from above explains why I'm not confident about (1):

    For ptr-to-int transmutes, I know that they will probably remove
    provenance, hence I am a bit cautious about using them for ptr-to-ptr or
    ref-to-ref.

The reason I'm confident about (2) is that that is the canonical way to
cast the type of a reference pointing to an `!Sized` value.

---
Cheers,
Benno
Tamir Duberstein March 27, 2025, 2:15 p.m. UTC | #15
On Wed, Mar 26, 2025 at 6:15 PM Benno Lossin <benno.lossin@proton.me> wrote:
>
> On Wed Mar 26, 2025 at 11:09 PM CET, Tamir Duberstein wrote:
> > On Wed, Mar 26, 2025 at 5:09 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
> >> > On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >> >> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> >> >> >
> >> >> > Yeah, we should do this - but again: not relevant in this discussion.
> >> >>
> >> >> I think it's pretty relevant.
> >> >
> >> > It's not relevant because we're no longer talking about transmuting
> >> > pointer to pointer. The two options are:
> >> > 1. transmute reference to reference.
> >> > 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
> >> > `ptr_as_ptr`), reborrow pointer to reference.
> >> >
> >> > If anyone can help me understand why (2) is better than (1), I'd
> >> > certainly appreciate it.
> >>
> >> I am very confident that (2) is correct. With (1) I'm not sure (see
> >> above), so that's why I mentioned it.
> >
> > Can you help me understand why you're confident about (2) but not (1)?
>
> My explanation from above explains why I'm not confident about (1):
>
>     For ptr-to-int transmutes, I know that they will probably remove
>     provenance, hence I am a bit cautious about using them for ptr-to-ptr or
>     ref-to-ref.
>
> The reason I'm confident about (2) is that that is the canonical way to
> cast the type of a reference pointing to an `!Sized` value.

Do you have a citation, other than the transmute doc?
Tamir Duberstein March 27, 2025, 7:44 p.m. UTC | #16
On Thu, Mar 27, 2025 at 10:15 AM Tamir Duberstein <tamird@gmail.com> wrote:
>
> On Wed, Mar 26, 2025 at 6:15 PM Benno Lossin <benno.lossin@proton.me> wrote:
> >
> > On Wed Mar 26, 2025 at 11:09 PM CET, Tamir Duberstein wrote:
> > > On Wed, Mar 26, 2025 at 5:09 PM Benno Lossin <benno.lossin@proton.me> wrote:
> > >> On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
> > >> > On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
> > >> >> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
> > >> >> >
> > >> >> > Yeah, we should do this - but again: not relevant in this discussion.
> > >> >>
> > >> >> I think it's pretty relevant.
> > >> >
> > >> > It's not relevant because we're no longer talking about transmuting
> > >> > pointer to pointer. The two options are:
> > >> > 1. transmute reference to reference.
> > >> > 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
> > >> > `ptr_as_ptr`), reborrow pointer to reference.
> > >> >
> > >> > If anyone can help me understand why (2) is better than (1), I'd
> > >> > certainly appreciate it.
> > >>
> > >> I am very confident that (2) is correct. With (1) I'm not sure (see
> > >> above), so that's why I mentioned it.
> > >
> > > Can you help me understand why you're confident about (2) but not (1)?
> >
> > My explanation from above explains why I'm not confident about (1):
> >
> >     For ptr-to-int transmutes, I know that they will probably remove
> >     provenance, hence I am a bit cautious about using them for ptr-to-ptr or
> >     ref-to-ref.
> >
> > The reason I'm confident about (2) is that that is the canonical way to
> > cast the type of a reference pointing to an `!Sized` value.
>
> Do you have a citation, other than the transmute doc?

Turns out this appeases clippy:

diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 80a9782b1c6e..7a6fc78fc314 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -240,9 +240,10 @@ pub fn read_raw(&mut self, out: &mut
[MaybeUninit<u8>]) -> Result {
     /// Fails with [`EFAULT`] if the read happens on a bad address,
or if the read goes out of
     /// bounds of this [`UserSliceReader`]. This call may modify
`out` even if it returns an error.
     pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
+        let out: *mut [u8] = out;
         // SAFETY: The types are compatible and `read_raw` doesn't
write uninitialized bytes to
         // `out`.
-        let out = unsafe { &mut *(out as *mut [u8] as *mut
[MaybeUninit<u8>]) };
+        let out = unsafe { &mut *(out as *mut [MaybeUninit<u8>]) };
         self.read_raw(out)
     }

Benno, would that work for you? Same in str.rs, of course.
Benno Lossin March 27, 2025, 10:17 p.m. UTC | #17
On Thu Mar 27, 2025 at 8:44 PM CET, Tamir Duberstein wrote:
> On Thu, Mar 27, 2025 at 10:15 AM Tamir Duberstein <tamird@gmail.com> wrote:
>> On Wed, Mar 26, 2025 at 6:15 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> > On Wed Mar 26, 2025 at 11:09 PM CET, Tamir Duberstein wrote:
>> > > On Wed, Mar 26, 2025 at 5:09 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> > >> On Wed Mar 26, 2025 at 8:06 PM CET, Tamir Duberstein wrote:
>> > >> > On Wed, Mar 26, 2025 at 1:36 PM Benno Lossin <benno.lossin@proton.me> wrote:
>> > >> >> On Wed Mar 26, 2025 at 5:57 PM CET, Tamir Duberstein wrote:
>> > >> >> >
>> > >> >> > Yeah, we should do this - but again: not relevant in this discussion.
>> > >> >>
>> > >> >> I think it's pretty relevant.
>> > >> >
>> > >> > It's not relevant because we're no longer talking about transmuting
>> > >> > pointer to pointer. The two options are:
>> > >> > 1. transmute reference to reference.
>> > >> > 2. coerce reference to pointer, `as` cast pointer to pointer (triggers
>> > >> > `ptr_as_ptr`), reborrow pointer to reference.
>> > >> >
>> > >> > If anyone can help me understand why (2) is better than (1), I'd
>> > >> > certainly appreciate it.
>> > >>
>> > >> I am very confident that (2) is correct. With (1) I'm not sure (see
>> > >> above), so that's why I mentioned it.
>> > >
>> > > Can you help me understand why you're confident about (2) but not (1)?
>> >
>> > My explanation from above explains why I'm not confident about (1):
>> >
>> >     For ptr-to-int transmutes, I know that they will probably remove
>> >     provenance, hence I am a bit cautious about using them for ptr-to-ptr or
>> >     ref-to-ref.
>> >
>> > The reason I'm confident about (2) is that that is the canonical way to
>> > cast the type of a reference pointing to an `!Sized` value.
>>
>> Do you have a citation, other than the transmute doc?

Not that I am aware of anything.

> Turns out this appeases clippy:
>
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index 80a9782b1c6e..7a6fc78fc314 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -240,9 +240,10 @@ pub fn read_raw(&mut self, out: &mut
> [MaybeUninit<u8>]) -> Result {
>      /// Fails with [`EFAULT`] if the read happens on a bad address,
> or if the read goes out of
>      /// bounds of this [`UserSliceReader`]. This call may modify
> `out` even if it returns an error.
>      pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
> +        let out: *mut [u8] = out;
>          // SAFETY: The types are compatible and `read_raw` doesn't
> write uninitialized bytes to
>          // `out`.
> -        let out = unsafe { &mut *(out as *mut [u8] as *mut
> [MaybeUninit<u8>]) };
> +        let out = unsafe { &mut *(out as *mut [MaybeUninit<u8>]) };
>          self.read_raw(out)
>      }

Seems like your email client auto-wrapped that :(

> Benno, would that work for you? Same in str.rs, of course.

For this specific case, I do have a `cast_slice_mut` function I
mentioned in the other thread, but that is still stuck in the untrusted
data series, I hope that it's ready tomorrow or maybe next week. I'd
prefer if we use that (since its implementation also doesn't use `as`
casts :). But if you can't wait, then the above is fine.

---
Cheers,
Benno
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 2e9eca8b7671..081b5fa2aa81 100644
--- a/Makefile
+++ b/Makefile
@@ -488,6 +488,7 @@  export rust_common_flags := --edition=2021 \
 			    -Wclippy::no_mangle_with_rust_abi \
 			    -Wclippy::ptr_as_ptr \
 			    -Wclippy::ptr_cast_constness \
+			    -Wclippy::ref_as_ptr \
 			    -Wclippy::undocumented_unsafe_blocks \
 			    -Wclippy::unnecessary_safety_comment \
 			    -Wclippy::unnecessary_safety_doc \
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index b105a0d899cc..2b69016070c6 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -27,6 +27,7 @@ 
 #[allow(dead_code)]
 #[allow(clippy::cast_lossless)]
 #[allow(clippy::ptr_as_ptr)]
+#[allow(clippy::ref_as_ptr)]
 #[allow(clippy::undocumented_unsafe_blocks)]
 mod bindings_raw {
     // Manual definition for blocklisted types.
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 4063f09d76d9..37cc03d1df4c 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -136,7 +136,8 @@  impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> {
     fn as_ptr(&self) -> *const T::RawType {
         // This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance
         // to access the sentinel.
-        (self as *const Self).cast()
+        let this: *const Self = self;
+        this.cast()
     }
 
     fn id(&self, index: usize) -> &T::RawType {
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 9e2639aee61a..366e23dc0803 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -359,12 +359,13 @@  impl core::ops::Deref for File {
     type Target = LocalFile;
     #[inline]
     fn deref(&self) -> &LocalFile {
+        let this: *const Self = self;
         // SAFETY: The caller provides a `&File`, and since it is a reference, it must point at a
         // valid file for the desired duration.
         //
         // By the type invariants, there are no `fdget_pos` calls that did not take the
         // `f_pos_lock` mutex.
-        unsafe { LocalFile::from_raw_file((self as *const Self).cast()) }
+        unsafe { LocalFile::from_raw_file(this.cast()) }
     }
 }
 
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 40034f77fc2f..6233af50bab7 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -29,7 +29,7 @@  pub const fn is_empty(&self) -> bool {
     #[inline]
     pub const fn from_bytes(bytes: &[u8]) -> &Self {
         // SAFETY: `BStr` is transparent to `[u8]`.
-        unsafe { &*(bytes as *const [u8] as *const BStr) }
+        unsafe { &*(core::mem::transmute::<*const [u8], *const Self>(bytes)) }
     }
 
     /// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
@@ -290,7 +290,7 @@  pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError
     #[inline]
     pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
         // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
-        unsafe { &mut *(bytes as *mut [u8] as *mut CStr) }
+        unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut Self>(bytes)) }
     }
 
     /// Returns a C pointer to the string.
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 80a9782b1c6e..c042b1fe499e 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -242,7 +242,7 @@  pub fn read_raw(&mut self, out: &mut [MaybeUninit<u8>]) -> Result {
     pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
         // SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to
         // `out`.
-        let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) };
+        let out = unsafe { &mut *(core::mem::transmute::<*mut [u8], *mut [MaybeUninit<u8>]>(out)) };
         self.read_raw(out)
     }
 
@@ -348,6 +348,7 @@  pub fn write<T: AsBytes>(&mut self, value: &T) -> Result {
         if len > self.length {
             return Err(EFAULT);
         }
+        let value: *const T = value;
         // SAFETY: The reference points to a value of type `T`, so it is valid for reading
         // `size_of::<T>()` bytes.
         //
@@ -357,7 +358,7 @@  pub fn write<T: AsBytes>(&mut self, value: &T) -> Result {
         let res = unsafe {
             bindings::_copy_to_user(
                 self.ptr as *mut c_void,
-                (value as *const T).cast::<c_void>(),
+                value.cast::<c_void>(),
                 len,
             )
         };
diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs
index d5dab4dfabec..6230ba48201d 100644
--- a/rust/uapi/lib.rs
+++ b/rust/uapi/lib.rs
@@ -16,6 +16,7 @@ 
     clippy::all,
     clippy::cast_lossless,
     clippy::ptr_as_ptr,
+    clippy::ref_as_ptr,
     clippy::undocumented_unsafe_blocks,
     dead_code,
     missing_docs,