Open
0 / 10 of 1 issue completed
Copy link
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-miriArea: The miri toolArea: The miri toolA-patternsRelating to patterns and pattern matchingRelating to patterns and pattern matchingC-bugCategory: This is a bug.Category: This is a bug.I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-langRelevant to the language teamRelevant to the language teamT-opsemRelevant to the opsem teamRelevant to the opsem teamT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
Description
@Amanieu found this fun example:
fn main() {
let x: &'static String;
let _ = *x;
}The borrow checker accepts this code. Miri says it has UB. Who is right?^^
The UB arises because let _ = place compiles to a "place mention", and PlaceMention(*x) still tries to construct the place *x which is ill-defined as x is uninitialized. (If you remove the *, it's fine because the place x exists and can be computed, it just denotes memory that hasn't been initialized yet. But *x describes a place that has no meaning.)
Cc @Nadrieril @rust-lang/types
Reacted by Tim (Theemathas) Chirananthavat, Max and Leon Schuermann
Metadata
Metadata
Assignees
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-miriArea: The miri toolArea: The miri toolA-patternsRelating to patterns and pattern matchingRelating to patterns and pattern matchingC-bugCategory: This is a bug.Category: This is a bug.I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-langRelevant to the language teamRelevant to the language teamT-opsemRelevant to the opsem teamRelevant to the opsem teamT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
Activity
[-]Borrow checker allows "place mention"-dereferencing an uninitialized refeernce[/-][+]Borrow checker allows "place mention"-dereferencing an uninitialized reference[/+]theemathas commentedon Oct 21, 2026
Another variant (UB in miri):
theemathas commentedon Oct 21, 2026
This, however, is apparently not UB according to miri.
theemathas commentedon Oct 22, 2026
miri, why do you think this is ok???
saethlin commentedon Oct 22, 2026
@theemathas I think that is a different bug. All your examples bisect to this:
My guess is #103208, before that nightly your examples encounter a compile error:
The original example has always compiled.
theemathas commentedon Oct 22, 2026
This compiles since 1.0.0:
Current miri thinks this is OK.
RalfJung commentedon Oct 22, 2026
@Nadrieril I think we have a bug somewhere about such
&patterns not being represented in MIR, don't we?maxdexh commentedon Oct 22, 2026
This also works for
Boxes that have been dropped:I suspect we will find this in more existing code than the version that does it on an uninit local.
Do we have any other types with builtin dereference logic? Other than references, raw pointers, and
Box?Nadrieril commentedon Oct 22, 2026
Hmmm, unsure if that bit is a bug: the place being tested would have derefs in it so nothing is missing, it's just that the enum has a single variant so we don't emit any read/read_discriminant of that place. Would we want to make sure that "we could read the discriminant" maybe, by adding a PlaceMention of the place being not-tested?
The OP however is very much a borrow-checker bug imo, since
*xreads a pointer fromn*xand there is none. Not unrelated to rust-lang/reference#2121.maxdexh commentedon Oct 22, 2026
I found an unsound miscompile based on this: #164738
I think we should just fix this by making all of these examples fail to compile outright.
RalfJung commentedon Oct 22, 2026
I do feel like we had an issue for that, since IMO we totally should emit such a read -- in particular for repr(C) enums where there can be actual data that has to be valid even for single-variant enums...
I think it was this issue: #147722
BoxyUwU commentedon Oct 27, 2026
With my types hat on I don't really have much of a mental model about the validity requirements of places. I would be more than happy for opsem to just figure that out and then someone can implement whatever makes sense.
My mental model here was that wildcard patterns just let you write whatever you want for the place expr being matched on. Given that we support
let _ = *null,*uninitdoesn't seem particularly different to me and would find it kind of subtle and surprising if there was a difference (though I think it would be fine language design wise to say there is a difference).let &Foo = *uninitworking is surprising to me though 😅Nadrieril commentedon Oct 27, 2026
Opsemwise places are memory locations, so place evaluation should produce something that has a known address. Then
let _just means "do nothing with that place". That's the criterion I'd want: borrow-checking should ensure that all places can be evaluated enough to know their address. This concretely means that:let _ = uninit;causes the local to be allocated, orlet _ = uninit;is statically rejected, I don't care);This allows
let _ = *null;(the null pointer has a known address) and rejectslet _ = *uninit;.BoxyUwU commentedon Oct 27, 2026
Seems reasonable