-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CTFE/Miri engine Pointer type overhaul #87123
Conversation
Some changes occured to the CTFE / Miri engine cc @rust-lang/miri Some changes occured to rustc_codegen_cranelift cc @bjorn3 Some changes occured to the CTFE / Miri engine cc @rust-lang/miri |
This comment has been minimized.
This comment has been minimized.
c7436a8
to
b7822c4
Compare
This comment has been minimized.
This comment has been minimized.
b7822c4
to
cb61d35
Compare
…sion infallible This resolves all the problems we had around "normalizing" the representation of a Scalar in case it carries a Pointer value: we can just use Pointer if we want to have a value taht we are sure is already normalized.
…ecated Scalar methods
cb61d35
to
8932aeb
Compare
// We know `offset` is relative to the allocation, so we can use `into_parts`. | ||
let (data, start) = match ecx.scalar_to_ptr(a.check_init().unwrap()).into_parts() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could into_parts assert this flag internally? Or does miri also have a need for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah Miri needs to access the offset
to compare between Pointer<AllocId>
(address is relative) and Pointer<Tag>
(address is absolute).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I actually did think of a way to make this more type-safe: the Provenance
trait could have an associated type Offset
, and a function wrap_offset(Size) -> Offset
. Then into_parts
would return Offset
, so code generic in Tag
would actually not know the type Offset
and this could not use it wrong.
Then we might go even further and make the Pointer::offset
field be of type Offset
... though at that point we cannot define generic pointer arithmetic methods any more so we'd need some more methods in the Provenance
trait.
But I am not sure if that's worth it. I had one bug caused by mis-interpreting a relative offset as absolute, and this would not have caught it (since the bug was about pointers stored inside an Allocation
, where the offset is part of the byte array anyway).
// so ptr-to-int casts are not possible (since we do not know the global physical offset). | ||
const OFFSET_IS_ADDR: bool = false; | ||
|
||
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a custom formatting function? Couldn't this be an impl on Pointer<AllocId>
directly, allowing all aggregates containing Pointer
to derive their Debug
impls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how. The Tag
type affects how the Pointer
itself is rendered:
Pointer<AllocId>
:alloc123+0x13
Pointer<Tag>
:0x12defg60[alloc123]<Stacked Borrows info>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm mainly unhappy about the roundabout formatting stuff that requires one to essentially write the derived impl by hand.
Yeah I am unhappy about that as well.^^ Open to suggestions for how to do this better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can miri implement Display for Pointer since Tag is a miri-internal type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't that only work for "fundamental" types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh also that would not help -- the generic code in rustc_mir::interpret
needs to know for sure that it can debug-print pointers. So we need something generic.
Is it possible to add Pointer<Self::PointerTag>: Debug
as a requirement to the Machine
trait?^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to add
Pointer<Self::PointerTag>: Debug
as a requirement to theMachine
trait?^^
Not in a useful way (you'd have to repeat the bound at every usage site of Machine
).
but you could keep your fmt
function and only implement Debug
manually on Pointer<Tag: Provenance>
and then you should be able to derive Debug
everywhere else, as long as you add the Tag: Provenance
bound to all the types instead of only on the impls. It's not nice, but nicer than doing manual trivial impls everywhere I think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thinking about this again, it's not too bad, so we can merge and figure out improvements later
The design lgtm in general, I'm mainly unhappy about the roundabout formatting stuff that requires one to essentially write the derived impl by hand. |
This comment has been minimized.
This comment has been minimized.
310f41f
to
4e28065
Compare
I pushed some more commits, mostly because changes were needed to get Miri to work again. One change is rather unfortunate: I had to give the An extremely coarse benchmark ( |
This comment has been minimized.
This comment has been minimized.
6b1ef0d
to
7c720ce
Compare
a091a22
to
a5299fb
Compare
r=me if you want, unless you are already working on the things we discussed and want to get them into this PR |
Yeah I am already experimenting now.^^ |
8c7bb33
to
c3ed171
Compare
This leads to an unnecessary I did not yet do this for |
Ah, with that last commit this PR actually has a net negative line count. :) |
I wish the derive macro would support adding extra where clauses...
c3ed171
to
efbee50
Compare
@bors r+ |
📌 Commit efbee50 has been approved by |
☀️ Test successful - checks-actions |
Tested on commit rust-lang/rust@c78ebb7. Direct link to PR: <rust-lang/rust#87123> 💔 miri on windows: test-pass → build-fail (cc @eddyb @RalfJung @oli-obk). 💔 miri on linux: test-pass → build-fail (cc @eddyb @RalfJung @oli-obk).
adjust Miri to Pointer type overhaul This is the Miri side of rust-lang/rust#87123. This was a lot more work than I expected... lucky enough it is also (hopefully) the last large-scale refactoring I will do.^^ Fixes #224
This fixes the long-standing problem that we are using
Scalar
as a type to represent pointers that might be integer values (since they point to a ZST). The main problem is that with int-to-ptr casts, there are multiple ways to represent the same pointer as aScalar
and it is unclear if "normalization" (i.e., the cast) already happened or not. This leads to ugly methods likeforce_mplace_ptr
andforce_op_ptr
.Another problem this solves is that in Miri, it would make a lot more sense to have the
Pointer::offset
field represent the full absolute address (instead of being relative to theAllocId
). This means we can do ptr-to-int casts without access to any machine state, and it means that the overflow checks on pointer arithmetic are (finally!) accurate.To solve this, the
Pointer
type is made entirely parametric over the provenance, so that we can usePointer<AllocId>
insideScalar
but usePointer<Option<AllocId>>
when accessing memory (whereNone
represents the case that we could not figure out anAllocId
; in that case theoffset
is an absolute address). Moreover, theProvenance
trait determines if a pointer with a given provenance can be cast to an integer by simply dropping the provenance.I hope this can be read commit-by-commit, but the first commit does the bulk of the work. It introduces some FIXMEs that are resolved later.
Fixes rust-lang/miri#841
Miri PR: rust-lang/miri#1851
r? @oli-obk