Make retags an implicit part of typed copies#154341
Make retags an implicit part of typed copies#154341RalfJung wants to merge 1 commit intorust-lang:mainfrom
Conversation
This comment has been minimized.
This comment has been minimized.
dbabc07 to
c5a3e40
Compare
This comment has been minimized.
This comment has been minimized.
c5a3e40 to
df515dd
Compare
|
@bors try |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Make retags an implicit part of typed copies
This comment has been minimized.
This comment has been minimized.
df515dd to
76c8c9d
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
|
Looks like enabling validation of references just to keep retags working in const-eval was not a good idea... |
76c8c9d to
d79e607
Compare
|
@bors try |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Make retags an implicit part of typed copies
This comment has been minimized.
This comment has been minimized.
9b5b622 to
2a1bbaa
Compare
This comment has been minimized.
This comment has been minimized.
2a1bbaa to
b0c8a17
Compare
|
@bors try jobs=dist-x86_64-linux |
This comment has been minimized.
This comment has been minimized.
Make retags an implicit part of typed copies try-job: dist-x86_64-linux
This comment has been minimized.
This comment has been minimized.
1a60ecb to
c15e5b2
Compare
|
Some changes occurred in src/tools/clippy cc @rust-lang/clippy The Miri subtree was changed cc @rust-lang/miri Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri, @oli-obk, @lcnr Some changes occurred to constck cc @fee1-dead Some changes occurred in coverage instrumentation. cc @Zalathar Some changes occurred in match lowering cc @Nadrieril This PR changes MIR cc @oli-obk, @JakobDegen, @vakaras Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred to the CTFE machinery This PR changes rustc_public cc @oli-obk, @celinval, @ouz-a, @makai410 Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter |
|
r? @fee1-dead rustbot has assigned @fee1-dead. Use Why was this reviewer chosen?The reviewer was selected based on:
|
| // knows what is supposed to happen here -- retag or not? `CopyForDeref` | ||
| // later turns into a no-retag assignment so probably maybe that's also | ||
| // what we need here. | ||
| Rvalue::Use(Operand::Copy(deref_place), WithRetag::No) |
There was a problem hiding this comment.
Cc @beepster4096 maybe you can help us with this.
There was a problem hiding this comment.
GVN (and also other MIR passes) has a somewhat non-obvious choice to make for these retags... either we ensure that the values that get replaced are all being retagged already anyway, or the new assignments they insert must be no-retag. We have to avoid a situation where such a pass adds a retag to a value that originally wasn't going to be retagged. I don't understand how GVN works so I decided to ignore this pass for now (and leave it as "always retag" to avoid a huge diff in mir-opt). This should be cleaned up in a follow-up PR. For the other passes I think I made sound choices but I am not fully confident about this.
There was a problem hiding this comment.
This pass doesn't track whether the constant it encounters are retagged or not, and I couldn't figure out if there could be non-integers involved here, so I just made the assignments it introduces no-retag to ensure we don't add incorrect retags. (Not retagging is the safe option in the sense that it's always allowed for remove retags, but not to add them.)
| ); | ||
| let mut helps = vec![operation_summary(&op.info.summary(), self.history.id, op.range)]; | ||
| if op.info.in_field { | ||
| helps.push(format!("errors for retagging in fields are fairly new; please reach out to us (e.g. at <https://rust-lang.zulipchat.com/#narrow/stream/269128-miri>) if you find this error troubling")); |
There was a problem hiding this comment.
We have done field retagging long enough now, I think we can remove this message. Instead, the with_validation_path machinery prints a path showing where in the value the relevant reference was encountered.
| | | ||
| LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | ||
| | ^^^^^^ | ||
| | ^^^^^^^^^^^^^^^^^^^^^^ |
There was a problem hiding this comment.
This span changes because we're now transmuting the input of the transmute again as part of the transmute operation.
There was a problem hiding this comment.
These tests don't fail any more since we can no longer disable validation without disabling alias checks. I moved them to "pass". They don't really test the original issue any more but they seem worth keeping around as nasty corner cases.
There was a problem hiding this comment.
I wasn't sure if there could ever be non-integers in the values we are copying here, so it seemed safer to not add any retags.
This comment has been minimized.
This comment has been minimized.
|
Miri performance numbers are positive throughout. :) |
8f6343a to
443e1d2
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
443e1d2 to
d298feb
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
Yay, CI is green. :) @fee1-dead as randomly selected reviewer for a big PR like this -- please let me know if you're comfortable reviewing this (in due time of course, no rush), or if I should go look for someone else. |
| ) -> InterpResult<'tcx, Option<ImmTy<'tcx, CtfeProvenance>>> { | ||
| if matches!(ecx.machine.retag_mode, RetagMode::None | RetagMode::Raw) { | ||
| return interp_ok(None); | ||
| } |
There was a problem hiding this comment.
out of curiosity -- what's the difference between Raw and None for RetagMode?
There was a problem hiding this comment.
A Raw retag does more than a default retag: in Stacked Borrows, when it finds a raw pointer, it will retag that. (In Tree Borrows, default retags and raw retags are equivalent.)
A None retag does less than a default retag. It doesn't retag anything.
| _ if ty.is_box_global(*this.tcx) => { | ||
| // The `None` marks this as a Box. | ||
| NewPermission::new(ty.builtin_deref(true).unwrap(), None, mode, this) |
There was a problem hiding this comment.
(apologies if this is not the right place for asking; happy to open a zulip thread) i had never noticed this; is it documented somewhere that only Box<T, Global> gets retags and effectively has aliasing validity? always assumed it was any Box!
There was a problem hiding this comment.
There has been some prior discussion and there are Miri testcases that show it would be UB to also require uniqueness for non-global Boxes, for examples of code that is meant to be valid with local allocators (at least that's what I am assuming). So indeed probably best to take this to Zulip.
View all comments
Ever since Stacked Borrows was first implemented in Miri, that was done with
Retagstatements: given a place (usually a local variable), those statements find all references stored inside the place and refresh their tags to ensure the aliasing requirements are upheld. However, this is a somewhat unsatisfying approach for multiple reasons:Retagstatements. Over time, the AddRetag pass settled on one possible answer to this, but it wasn't very canonical.*ptr = expr, if the assignment involves copying a reference, we probably want to do a retag -- but if we do aRetag(*ptr)as the next instruction, it can be non-trivial to argue that this even retags the right value, so we refrained from doing retags in that case. This has come up as a potential issue for Rust making better use of LLVM "captures" annotations.noalias. What does that even mean? How do MIR optimization passes interact with retags? These are questions we have to figure out to make better use of aliasing information, but currently we can't even really ask such questions.I think we should resolve all that by making retags part of what happens during a typed copy (a concept and interpreter infrastructure that did not exist yet when retags were initially introduced). Under this proposal, when executing a MIR assignment statement, what conceptually happens is as follows:
However, this semantics doesn't fully work: there's a mandatory MIR pass that turns expressions like
&mut ***ptrinto intermediate deref's. Those must not do any retags. So far this happened because the AddRetag pass did not add retags for assignments to deref temporaries, but that information is not recorded in cross-crate MIR. Therefore I instead added a field toRvalue::Useto indicate whether this value should be retagged or not. A non-retagging copy seems like a sufficiently canonical primitive that we should be able to express it. Dealing with the fallout from that is a large chunk of the overall diff. (I also considered adding this field toStatementKind::Assigninstead, but decided against that as we only actually need it forRvalue::Use. I am not sure if this was the right call...)This neatly answers the question of when retags should occur, and handles cases like
*ptr = expr. It avoids traversing values twice in Miri. It makes codegen's use ofnoaliassound wrt the actual MIR that it is working on. It also gives us a target semantics to evaluate MIR opts against. However, I did not carefully check all MIR opts -- in particular, GVN needs a thorough look under the new semantics. (But this PR doesn't make things any worse for normal compilation where the retag indicator is anyway ignored.)Another side-effect of this PR is that
-Zmiri-disable-validationnow also disables alias checking. It'd be nicer to keep them orthogonal but I find this an acceptable price to pay.