-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
slice::from_raw_parts
returns a different address in const context for u8
#105536
Comments
@rustbot label A-const-eval, T-compiler, A-slice In the linked URLO discussion, @LegionMammal978 mentioned some part of the compiler that seems relevant for why this behavior only affects Maybe they also have more insight into whether this kind of behavior classifies as intended or bug, since there definitely are cases where reference addresses of |
It's not promotion related: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b89aaee74c5da29370ba7107576adc7a So I'm guessing some sort of codegen issue, because otherwise turning the reference back to a pointer in const land would cause the same issue, but it doesn't: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6ac87b271a9b495b6497015d95b57815 |
Minimized, and emphasizing the same thing oli just showed about this being related to the const item somehow, not a problem in MIR interpreting itself: assert_eq!(
// as_ptr INside the `const{}`
(const { (unsafe { std::slice::from_raw_parts(3 as *const u8, 0) }).as_ptr() }),
std::ptr::invalid(3),
); // PASSES
assert_eq!(
// as_ptr OUTside the `const{}`
(const { (unsafe { std::slice::from_raw_parts(7 as *const u8, 0) }) }).as_ptr(),
std::ptr::invalid(7),
); // FAILS, 0x56229d3aa00b != 0x7 |
It seems like the whole point of debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (data, start) = match a.to_pointer(ecx).unwrap().into_parts() {
(Some(alloc_id), offset) => {
(ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes())
}
(None, _offset) => (
ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
b"" as &[u8],
)),
0,
),
};
let len = b.to_machine_usize(ecx).unwrap();
let start = start.try_into().unwrap();
let len: usize = len.try_into().unwrap();
ConstValue::Slice { data, start, end: start + len } That is, a So the reference isn't transformed every time it's used, only in certain contexts, where the slice has to exit const-eval-land and become a real instantiated value. For instance, using a slice as a const-generic parameter triggers the same behavior (Playground): #![allow(incomplete_features)]
#![feature(adt_const_params)]
use std::slice::from_raw_parts;
struct AsPtr<const SLICE: &'static [u8]>;
impl<const SLICE: &'static [u8]> AsPtr<SLICE> {
const PTR: *const u8 = SLICE.as_ptr();
}
fn main() {
let ptr = AsPtr::<{ unsafe { from_raw_parts(1 as *const u8, 0) } }>::PTR;
println!("{ptr:p}");
} Notably, this only occurs when the slice is the entire constant value. The address isn't modified if the slice is a field of a struct, enum, or array. |
Considering that we got valtrees now, this will become more common. All addresses in type level constants are now de- or duplicated. For these ones that are not used in type level consts, we should just remove the ConstValue::Slice variant, as it is not needed anymore except potentially for perf, but we may be able to preserve that |
For the specific case of |
this issue is mitigated by #115764, and we can probably fix it entirely based on that change |
I think that PR should already fix this issue completely?
|
sweet. wanna add a regression test to the PR, too? |
Sure, will do. @mxk note that we do not guarantee that these pointers will always be equal. We always reserve the right to duplicate the values of But in this case the inequality was a symptom of the compiler doing some unnecessary work, and that's why it got fixed. |
some ConstValue refactoring In particular, use AllocId instead of Allocation in ConstValue::ByRef. This helps avoid redundant AllocIds when a `ByRef` constant gets put back into the interpreter. r? `@oli-obk` Fixes rust-lang/rust#105536
Possibly as a result of some u8-specific optimizations, a const
&[u8]
returned bystd::slice::from_raw_parts
has a different address than all other uses of the same expression. Forum discussion.I tried this code:
Playground
I expected to see this happen: All assertions should pass.
Instead, this happened:
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: