-
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
Keep valid scalar ranges attached to newtypes when dealing with their inner field. #97261
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
Thanks for the PR, @luqmana! This looks good to me (great tests!) but I'm not deeply familiar with the layout code and have run into surprises there recently. So, it would be good to get a second set of eyes on it: r? rust-lang/compiler (if @eddyb has time to take a look at this, that would be ideal) |
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've left some comments but before we proceed in either direction I want to check what the perf numbers are like.
@bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
⌛ Trying commit 7a2ea71d46532bf1c916462deb5d264865ef94ba with merge 078c002eef9695d4b5ad23da2d16ce3096b06451... |
☀️ Try build successful - checks-actions |
Queued 078c002eef9695d4b5ad23da2d16ce3096b06451 with parent 56fd680, future comparison URL. |
Finished benchmarking commit (078c002eef9695d4b5ad23da2d16ce3096b06451): comparison url. Instruction count
Max RSS (memory usage)Results
CyclesThis benchmark run did not return any relevant results for this metric. If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. @bors rollup=never Footnotes |
Reuse the valid scalar ranges of a newtype if it has a singular non-zero field.
7a2ea71
to
34a80f0
Compare
Could I get a new perf run? |
@bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
☀️ Try build successful - checks-actions |
Queued 3fa09c607228910837729e1e850ae97490c9d916 with parent 0a43923, future comparison URL. |
Finished benchmarking commit (3fa09c607228910837729e1e850ae97490c9d916): comparison url. Instruction count
Max RSS (memory usage)Results
CyclesResults
If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. @bors rollup=never Footnotes |
So, based on MIR semantics as currently documented, I do not believe this is sound (and would lead to miscompilations at least in conjunction with dest prop as specced above). We currently specify that the validity of a load depends on the type at which the load operation happens. This would mean that for #[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
pub struct NonZeroUsize(usize); MIR like this:
is not UB because the load in the second assignment is at type
is UB because the load is at type Of course, that is not to say that this change is undesirable - it does seem nice to have this. But we should change the MIR documentation to reflect an alternative that supports this first. Essentially, the way that I think we would need to do this is to pass the validity range down through field projections the same way we do it for metadata. This doesn't make much sense for generic types though, although I suppose we can just ban the annotations on generic types? (Maybe we do already?) @RalfJung thoughts? Edit: The suggestion above comes with trouble actually. Now optimizing _10 = &mut _2.0;
*_10 = _3; to |
I think you meant to reference rust-lang/unsafe-code-guidelines#84. Good catch!
|
Ah, yeah, thanks for linking the right issue. Fwiw, I'm not so convinced we don't want code like that UB - but if we make it UB, that should be done in conjunction with an appropriate resolution to the UCG issue, and not on its own |
Thanks @JakobDegen & @RalfJung for chiming in and the UCG link! Looks like there's a lot more subtleties to this so gonna take some time to look into that. @rustbot label +S-blocked |
going through my assigned prs rn, not really something I can review even if it weren't blocked r? @RalfJung for now |
Sorry, I cannot review this -- I can talk without end about MIR semantics conceptually, but that is quite different from actually implementing them in the LLVM backend. ;) However, this is also a language change I think, and would need T-lang signoff. This introduces UB Miri does not currently detect. My personal opinion is this should not be UB. |
Cc @rust-lang/lang
My personal opinion is hence that we should not merge this. I would even prefer us to commit to not making this code UB. |
@RalfJung I don't think the scope of this question needs to be this wide. If we are only concerned about this PR, there is no need to involve references. It suffices to ask whether this code is UB: #![feature(rustc_attrs)]
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero(usize);
let x: NonZero = NonZero(5);
x.0 = 0;
dbg!(x.0);
x.0 = 5 This PR would make the access inside I also think we should avoid making a decision on UCG#77 right now. I feel pretty strongly that we need to investigate further how it interacts with non-freeze enum retagging and that whole chain of complexity. (For anyone who wants details) Separately of the concrete question though, I am not quite sure what is being asked of T-Lang here. Are we really asking for them to commit to [whichever code] not being UB? I would find that surprising, as it feels like there are much more obvious parts of the memory model that do not have T-Lang approval yet. |
I don't think so. Your example is rust-lang/unsafe-code-guidelines#84, which is basically orthogonal to rust-lang/unsafe-code-guidelines#77. But the example at the top of #97161 is quite clearly about a reference. In particular, no matter how rust-lang/unsafe-code-guidelines#84 is resolved, the optimization requested in #97161 is not correct if validity is "shallow" for references. I assume, based on the description, that this PR implements that optimization. So this is definitely about rust-lang/unsafe-code-guidelines#77. |
Well, I don't think we should land this PR without deciding that we actually want this to be UB. Which we only get by resolving UCG#77. Not landing this PR doesn't mean it's not UB. But landing this PR means it is UB. The optimizations we do and attributes we emit are a lower bound on the UB we have. This PR adds more attributes, so it increases that lower bound, and that is what I am objecting. We're so close to finally catching up with the LLVM flags we emit in Miri, making sure we have our existing bases covered. This PR proposes to race ahead and emit more flags, make more promises to LLVM. This time I think we should design first, and then start adding attributes. I know that's a new strategy for us, so far we "have just always had" those LLVM attributes ( |
I've updated the example to show that that's not the case (or at least to show that
That's not necessarily true, but I don't want to get into that here. We can discuss more on Zulip.
Agreed. That makes me think that there isn't actually a T-Lang question here. I mean, I suppose we can ask, but I agree with you that I hope that the response is "that's a good question that we don't want to commit to right now" |
Okay so your example shows that both UCG#77 and UCG#84 to be resolved to evaluate whether this PR is sound. Fair. But UCG#84 alone is certainly not sufficient; the motivating example needs UCG#77.
Well, I would also be fine with closing this PR without going through T-lang. I just wanted to keep them in the loop to ensure that I am not going rogue here. @luqmana sorry that this is so hard, but whether you realized it when writing the code or not, your proposed change is a Big Deal and basically changing the specification of Rust. So I think the chances of it landing at this time are slim. |
Oh, no need to apologize! I like learning more about some of these subtle details. And don't worry, I figured this wasn't gonna be completely straight forward :P Alas, just been too busy to do anything more with this rn. Feel free to close this and the conversation can be moved to the issue instead. |
I agree with @RalfJung's proposal here: it should be fine for @RalfJung, is that an accurate statement of your proposal? If so, could we get a reference PR making this proposal, and we can FCP it for ratification? |
That depends on how exactly you define "dereference". :) For So memory is never accessed at the offending |
Fixes #97161 by keeping an "effective" scalar validity range on
PlaceRef
and propagating it for newtypes of primitives.