-
Notifications
You must be signed in to change notification settings - Fork 13.9k
CTFE/Miri engine Pointer type overhaul #87123
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
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+0x13Pointer<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>: Debugas a requirement to theMachinetrait?^^
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
Scalaras 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 aScalarand it is unclear if "normalization" (i.e., the cast) already happened or not. This leads to ugly methods likeforce_mplace_ptrandforce_op_ptr.Another problem this solves is that in Miri, it would make a lot more sense to have the
Pointer::offsetfield 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
Pointertype is made entirely parametric over the provenance, so that we can usePointer<AllocId>insideScalarbut usePointer<Option<AllocId>>when accessing memory (whereNonerepresents the case that we could not figure out anAllocId; in that case theoffsetis an absolute address). Moreover, theProvenancetrait 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