TL;DR: Charon needs more information regarding niche layouts, as otherwise we cannot reliably compute whether a tag is valid
The current information Charon outputs for an enum layout is actually not sufficient to detect some fun cases of UB reliably. I discovered this through this miri test.
In particular it has this enum:
enum Foo {
Var1, // variant 0, tag 2
Var2(bool), // variant 1, untagged (valid values are 0=false and 1=true)
Var3, // variant 2, tag 4
}
And then does this:
let invalid: Foo = mem::transmute(3u8);
assert!(matches!(invalid, Foo::Var2(_)));
Although line 1 is UB with validity checks, Miri allows disabling those, in which case instead we get UB on line 2 for a different reason:
- the
niche_variants range of the enum (which variants are niches) is 0..=2 (it includes 1, but 1 is the untagged variant)
- however using
3 is not valid, and is verified in const-eval by these lines
https://github.com/rust-lang/rust/blob/1b7d722f429f09c87b08b757d89c689c6cf7f6e7/compiler/rustc_const_eval/src/interpret/discriminant.rs#L177-L181
- basically, we're in the niche range (
0..=2) but we're using the untagged variant (1), so it's invalid
- however Charon currently only exports the fact variant 1 is niched and that variants 0 and 2 have tags 2 and 4 respectively; there is no information on what the niche range is; as such the only way to detect this UB is by deserialising the whole value with validity checks, which is "too much work", we should be able to detect it earlier.
The solution to this is extending TagEncoding::Niche to include the niche_variants range and niche_start, enabling client to reproduce the const-eval calculation of tags.
cc @firefighterduck this might be of interest to you :3
TL;DR: Charon needs more information regarding niche layouts, as otherwise we cannot reliably compute whether a tag is valid
The current information Charon outputs for an enum layout is actually not sufficient to detect some fun cases of UB reliably. I discovered this through this miri test.
In particular it has this enum:
And then does this:
Although line 1 is UB with validity checks, Miri allows disabling those, in which case instead we get UB on line 2 for a different reason:
niche_variantsrange of the enum (which variants are niches) is0..=2(it includes 1, but 1 is the untagged variant)3is not valid, and is verified in const-eval by these lineshttps://github.com/rust-lang/rust/blob/1b7d722f429f09c87b08b757d89c689c6cf7f6e7/compiler/rustc_const_eval/src/interpret/discriminant.rs#L177-L181
0..=2) but we're using the untagged variant (1), so it's invalidThe solution to this is extending
TagEncoding::Nicheto include theniche_variantsrange andniche_start, enabling client to reproduce the const-eval calculation of tags.cc @firefighterduck this might be of interest to you :3