-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
MIR: Do we allow accesing a moved place? #112564
Comments
@JakobDegen mentioned this optimisation before rust-lang/unsafe-code-guidelines#188 (comment) |
This code writes to a moved place instead. Both LLVM and Cranelift output 0, where as Miri output 1. For the same reason (function arguments are always a MIR temporary and no move-propagation), this currently cannot be reproduced using surface Rust. #![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
pub struct Inner {
tup: (usize, i32, f64),
}
pub struct Outer {
inner: Inner,
}
#[custom_mir(dialect = "runtime", phase = "initial")]
pub fn start() {
mir! {
let non_copy: Outer;
let fld_ptr: *mut (usize, i32, f64);
let unit: ();
{
non_copy.inner.tup = (0, 1, 0.);
let fld_ptr = core::ptr::addr_of_mut!(non_copy.inner.tup);
Call(unit, ret, write(fld_ptr, Move(non_copy.inner)))
}
ret = {
Return()
}
}
}
pub unsafe fn write(mut ptr_to_non_copy: *mut (usize, i32, f64), mut non_copy: Inner) {
(*ptr_to_non_copy).1 = 0;
println!("{}", non_copy.tup.1);
}
pub fn main() {
unsafe { start() };
} |
I think this falls in the scope of #71117 -- we don't currently have any proper spec for these |
miri: protect Move() function arguments during the call This gives `Move` operands a meaning specific to function calls: - for the duration of the call, the place the operand comes from is protected, making all read and write accesses insta-UB. - the contents of that place are reset to `Uninit`, so looking at them again after the function returns, we cannot observe their contents Turns out we can replace the existing "retag return place" hack with the exact same sort of protection on the return place, which is nicely symmetric. Fixes rust-lang/rust#112564 Fixes rust-lang#2927 This starts with a Miri rustc-push, since we'd otherwise conflict with a PR that recently landed in Miri. (The "miri tree borrows" commit is an unrelated cleanup I noticed while doing the PR. I can remove it if you prefer.) r? `@oli-obk`
miri: protect Move() function arguments during the call This gives `Move` operands a meaning specific to function calls: - for the duration of the call, the place the operand comes from is protected, making all read and write accesses insta-UB. - the contents of that place are reset to `Uninit`, so looking at them again after the function returns, we cannot observe their contents Turns out we can replace the existing "retag return place" hack with the exact same sort of protection on the return place, which is nicely symmetric. Fixes rust-lang/rust#112564 Fixes rust-lang/miri#2927 This starts with a Miri rustc-push, since we'd otherwise conflict with a PR that recently landed in Miri. (The "miri tree borrows" commit is an unrelated cleanup I noticed while doing the PR. I can remove it if you prefer.) r? `@oli-obk`
fn14()
dereferences a pointer to a place that has been moved to another function. Currently, Miri thinks this is fine, but this causes the compiled code to produce different results under different optimisation levels.At the moment, this is only reproducible with custom MIR, because when we build MIR from surface Rust we always create a temporary, so you cannot create a pointer to anything that will be directly moved into another function.
So either we should call this UB or codegen shouldn't rely on the assumption that a moved MIR place will never be used later.
cc @RalfJung
The text was updated successfully, but these errors were encountered: