-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Fix ICE on const eval of union field #47794
Fix ICE on const eval of union field #47794
Conversation
MIR's `Const::get_field()` attempts to retrieve the value for a given field in a constant. In the case of a union constant it was falling through to a generic `const_get_elt` based on the field index. As union fields don't have an index this caused an ICE in `llvm_field_index`. Fix by simply returning the current value when accessing any field in a union. This works because all union fields start at byte offset 0. The added test uses `const_fn` it ensure the field is extracted using MIR's const evaluation. The crash is reproducible without it, however. Fixes #47788
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @eddyb (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
|
||
union DummyUnion { | ||
field1: i32, | ||
field2: i32, |
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.
What happens if you make them different types, say, i64
for the second field`, and maybe do some arithmetic on it?
I can confirm that #46882 fixes this. My only concern is this a regression against stable as it's possible to crash nightly and beta (but not 1.23) with the following: union DummyUnion {
field1: i32,
field2: i32,
}
const UNION: DummyUnion = DummyUnion { field1: 1 };
fn read_field1() -> i32 {
const FIELD1: i32 = unsafe { UNION.field1 };
FIELD1
}
fn main() {
read_field1();
} |
Yes but what does stable do if the types aren't the same? It can't possibly work. Oh well. cc @rust-lang/compiler |
Also I think your test is still subtly cheating, try an union between |
This passes on both stable and this PR but ICEs on nightly and beta: type Field1 = u64;
type Field2 = (u32, u32);
union DummyUnion {
field1: Field1,
field2: Field2,
}
const UNION: DummyUnion = DummyUnion {
field1: 0xdeadbeeff00fb00f,
};
fn read_field1() -> Field1 {
const FIELD1: Field1 = unsafe { UNION.field1 };
FIELD1
}
fn read_field2() -> Field2 {
const FIELD2: Field2 = unsafe { UNION.field2 };
FIELD2
}
fn main() {
assert_eq!(read_field1(), 0xdeadbeeff00fb00f);
let (first, second) = read_field2();
assert_eq!(first, 0xf00fb00f);
assert_eq!(second, 0xdeadbeef);
} |
This is not supposed to work on stable. |
This code will get removed by #46882 and the underlying issue will be fixed. I'll add this test to my PR, it should simply work |
Yup, that finally kills it. Running this will segfault on stable and fail the assertion on my PR: type Field1 = u64;
type Field2 = (u32, u32);
union DummyUnion {
field1: Field1,
field2: Field2,
}
const UNION: DummyUnion = DummyUnion {
field1: 0xdeadbeeff00fb00f,
};
fn read_field2_1() -> u32 {
const FIELD2_1: u32 = unsafe { UNION.field2.1 };
FIELD2_1
}
fn main() {
assert_eq!(read_field2_1(), 0xdeadbeef);
} |
@bors r+ |
📌 Commit ed7e4e1 has been approved by |
I think we should merge this and backport it, it shouldn't allow anything that didn't work before. |
…r=eddyb Fix ICE on const eval of union field MIR's `Const::get_field()` attempts to retrieve the value for a given field in a constant. In the case of a union constant it was falling through to a generic `const_get_elt` based on the field index. As union fields don't have an index this caused an ICE in `llvm_field_index`. Fix by simply returning the current value when accessing any field in a union. This works because all union fields start at byte offset 0. The added test uses `const_fn` it ensure the field is extracted using MIR's const evaluation. The crash is reproducible without it, however. Fixes #47788 r? @eddyb
☀️ Test successful - status-appveyor, status-travis |
@eddyb What's the process for backporting? Should I open a PR against the beta branch? |
@etaoins We first have to accept it and then we typically batch them. |
Accepting for backport. |
MIR's
Const::get_field()
attempts to retrieve the value for a given field in a constant. In the case of a union constant it was falling through to a genericconst_get_elt
based on the field index. As union fields don't have an index this caused an ICE inllvm_field_index
.Fix by simply returning the current value when accessing any field in a union. This works because all union fields start at byte offset 0.
The added test uses
const_fn
it ensure the field is extracted using MIR's const evaluation. The crash is reproducible without it, however.Fixes #47788
r? @eddyb