-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Allow &raw [mut | const]
for union field in safe
#141469
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
base: master
Are you sure you want to change the base?
Conversation
Failed to set assignee to
|
cc @RalfJung |
&raw [mut | const]
for union field in safe
Uh, the unsafety checker is not actually code I know very well, sorry. |
The macros just expand to |
This comment has been minimized.
This comment has been minimized.
I will debug this later today but this is very weird |
b006128
to
43892d3
Compare
This comment has been minimized.
This comment has been minimized.
b60d3ff
to
fc03435
Compare
This comment has been minimized.
This comment has been minimized.
9ccf35d
to
cde9fa0
Compare
@rustbot ready |
Well, it's an insta-stable change in semantics and as such it warrants an FCP, as simple as that ;) Likely a T-lang or T-lang+T-opsem FCP and for that it needs a lang nomination first. |
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
Makes sense to me. Getting the pointer is fine, and inside the allocation of the union the fields have to be @rust-rfcbot reviewed |
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.
This PR causes UB:
union A {
a: usize,
b: &'static &'static B,
}
union B {
c: usize,
}
fn main() {
let a = A { a: 0 };
let p = &raw const (**a.b).c;
println!("{p:?}");
}
Specifically, using global state for the nested union access is not the right choice, because it means that we suppress union accesses in arbitrary nested accesses. I don't think we should (or need to) be using a field on UnsafetyVisitor
to properly implement this behavior.
Good catch, thanks! I was tried to reproduce a way to exploit this global state and am currently thinking about how to do it better. If anyone has ideas, I would appreciate it |
tests/ui/union/union-unsafe.rs
Outdated
// Test for union fields chain, this should be allowed | ||
#[derive(Copy, Clone)] | ||
union Inner { | ||
a: u8, | ||
} | ||
|
||
union MoreInner { | ||
moreinner: ManuallyDrop<Inner>, | ||
} | ||
|
||
union LessOuter { | ||
lessouter: ManuallyDrop<MoreInner>, | ||
} | ||
|
||
union Outer { | ||
outer: ManuallyDrop<LessOuter>, | ||
} | ||
|
||
let super_outer = Outer { | ||
outer: ManuallyDrop::new(LessOuter { | ||
lessouter: ManuallyDrop::new(MoreInner { | ||
moreinner: ManuallyDrop::new(Inner { a: 42 }), | ||
}), | ||
}), | ||
}; | ||
|
||
let ptr = &raw const super_outer.outer.lessouter.moreinner.a; |
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 believe this should compile. These implicitly desugar to derefs:
let ptr = &raw const (*(*(*super_outer.outer).lessouter).moreinner).a;
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, projecting into a ManuallyDrop
should still be unsafe.
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.
And allowing arbitrary derefs here is also UB, of course:
use std::ops::Deref;
union A {
a: usize,
b: B,
}
#[derive(Copy, Clone)]
struct B(&'static str);
impl Deref for B {
type Target = C;
fn deref(&self) -> &C {
println!("{:?}", self.0);
&C { c: 0 }
}
}
union C {
c: usize,
}
fn main() {
let a = A { a: 0 };
let p = &raw const (*a.b).c;
println!("{p:?}");
}
// Or not implicit:
fn main2() {
let a = A { a: 0 };
let p = &raw const a.b.c;
println!("{p:?}");
}
I believe the actual implementation of this feature can be significantly simplified: https://github.com/compiler-errors/rust/pull/new/proper-union-field-unsafety |
Yes, your approach looks more simple and fixes things above because of no leaking global state in chains. Would you mind pushing the changes directly to this PR? |
I could push directly but I also would like for you to add additional tests exercising the corner cases I pointed out, so I think you can just push the changes when you get around to adding those tests. |
3db681f
to
4024f37
Compare
This PR was rebased onto a different master 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. |
Not sure if I shoulded to split this test into separate files |
4024f37
to
23f1767
Compare
fixes #141264
r? @Veykril
Unresolved questions:
&raw
context) (Allow&raw [mut | const]
for union field rust-analyzer#19867)addr_of!
andaddr_of_mut!
as well? In current version they both (&raw
andaddr_of!
) are allowed (They are the same)