Open
Description
What it does
Recommends avoiding &mut
to *const
coercions
Advantage
As described in rust-lang/rust#56604, these coercions have surprising behavior that can result in unsoundness in unsafe
code. They implicitly first coerce to a shared reference (&
), with the result that the resulting raw pointer may have different semantics than a seemingly-equivalent raw pointer produced by first coercing to *mut
and then casting to *const
. (I say "may" because this depends on how references are formalized in Rust - Stacked Borrows, Tree Borrows, etc.)
Drawbacks
Authors might be relying on this behavior. It strikes me as unlikely to be common - anecdotally, seasoned unsafe
programmers I've spoken did not know about this behavior.
Example
let x = &mut 0;
let y: *const i32 = x;
Could be written as:
let x = &mut 0;
let y: *mut i32 = x;
let y = y.cast_const();
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
RalfJung commentedon May 12, 2024
FWIW, I consider this a bug in our spec that I want to fix. Not sure if it's worth making clippy deal with that.
joshlf commentedon May 13, 2024
Agreed, but do we have a concrete timeline on this? My experience with Rust (as with many open source projects) is that it's hard to make promises about how quickly things will move since it's mostly volunteers, and so it's risky to say "let's not do this because soon it won't matter" since "soon" could end up being multiple years.
In order to deal with this reality, I usually prefer to put all of the irons in the fire at the same time so that hopefully something will pan out in relatively short order. E.g., in google/zerocopy#29, we needed some way of computing layout information for an unsized type. Since we weren't sure what we could stabilize at what pace, we "raced" three different approaches (see the "Support deriving
KnownLayout
for unsized types" bullet):offset_of!
and expand it to support unsized typessize_of_val_raw
andalign_of_val_raw
repr(C)
layout algorithm manuallyIn the end, we managed to stabilize
offset_of!
, but we didn't make progress on getting it to support unsized types. We didn't make much progress on stabilizing{size,align}_of_val_raw
. We ended up taking the approach of reimplementing therepr(C)
layout algorithm manually.My point in mentioning that example is just to suggest that we might want to write this lint anyway as a hedge unless we're confident that the spec bug will be fixed in a reliably short time frame.
RalfJung commentedon May 13, 2024
It seems strange to land a lint for something that largely only exists in an experimental, never-approved memory model I proposed.
Are you saying having this issue affect Miri executions (as that's the only thing it affects) is bad enough to warrant a lint?
joshlf commentedon May 13, 2024
I'm confused - does rust-lang/rust#56604 not apply to the current language semantics?
RalfJung commentedon May 13, 2024
What do you mean by "current language semantics"? We have no aliasing model, other than the experiments implemented in Miri (SB, TB).
It doesn't affect LLVM codegen.
joshlf commentedon May 13, 2024
My point is that the implicit
&mut
to&
coercion does happen on today's Rust, right?IIUC, your point is that
&mut as *mut as *const
and& as *const
are semantically identical on today's Rust, and that they are only semantically distinguished under SB (and maybe also TB?), so the implicit&mut
to&
coercion is true-but-irrelevant on today's Rust?If that's right, then my thinking was that this is a forwards-compatibility issue. But I suppose if we promise to not formally adopt SB or TB (or something else) without first resolving this issue, then I agree that this is probably premature.
briansmith commentedon May 28, 2024
I'm in the process now of doing rewrites from:
to:
Basically, this is rewriting explicit cocersions of
&T
to*const T
to usefrom_ref
, which is documented as being "safer" than casts.This lint, if implemented, should also then pick up cases where
ptr::from_ref
is passed a&mut T
, because it has the same issue.I guess it should also detect this pattern then:
It seems like the real issue, though, is that
*const T
to*mut T
casts are extremely dangerous, just like in any language.ref_as_ptr
suggests usingptr::from_ref(r)
where it should instead suggestptr::from_mut(r)
forr: &mut T
. #12882