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(-)
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,
--
2.49.0
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)
> }
>
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.
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
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?
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
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.
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
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.
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
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.
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
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)?
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
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?
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.
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
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.".
© 2016 - 2026 Red Hat, Inc.