-
Notifications
You must be signed in to change notification settings - Fork 58
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
Can a &UnsafeCell<T>
and a &mut UnsafeCell<T>
alias?
#284
Comments
What you describe is not semantically different from reborrowing, which can be done in purely safe code: fn main() {
let mut a = String::from("Hello World!");
let b = &mut a;
println!("{:p}", b);
let c = &mut *b;
// ↑ Here, both `b` and `c` point to the same address
println!("{:p}", c);
println!("{:p}", b);
// ↑ Here, `c` is invalidated, because `b` reclaimed the exclusivity to `a`
// and trying to use it, would result in a compile-time error:
// println!("{:p}", c);
} The only difference is, that you have to manage the lifetimes yourself, i.e. Rust won't be complaining, if you do uncomment the last EDIT:
Assuming let my_var: *mut MyType = …;
let my_mut_ref: &mut MyType = unsafe { &mut *my_var }; and let my_var: *mut MyType = …;
let my_mut_ref: &mut MyType =
unsafe { transmute(my_var) }; have the same semantics, then I'd assume doing let my_var: *mut MyType = …;
let my_mut_ref: &mut UnsafeCell<MyType> =
unsafe { transmute(my_var) }; is valid, as well, because let my_original_var: MyType = …;
let my_cell_var: UnsafeCell<MyType> = UnsafeCell::new(my_original_var);
let my_var: *mut MyType = my_cell_var.get();
let my_mut_ref: &mut UnsafeCell<MyType> =
unsafe { transmute(my_var) }; is valid, too. However, transmuting
This implies to me, that you must go through |
It's precisely the lifetime's relationship I find slightly surprising. Consider this example: use std::cell::UnsafeCell;
fn transform<T>(from: &UnsafeCell<T>) -> &mut UnsafeCell<T> {
unsafe { &mut *(from.get() as *mut UnsafeCell<T>) }
}
fn main() {
let mut cell = UnsafeCell::new("Hello".to_string());
let derived = transform(&cell);
let ptr = cell.get();
println!("{:?} -> {:?}", ptr, derived.get_mut());
} I am surprised to see that A slight version of it is rejected, due to considering that use std::cell::UnsafeCell;
fn transform<T>(from: &UnsafeCell<T>) -> &mut UnsafeCell<T> {
unsafe { &mut *(from.get() as *mut UnsafeCell<T>) }
}
fn main() {
let mut cell = UnsafeCell::new("Hello".to_string());
let derived = transform(&cell);
println!("{:?} -> {:?}", cell.get_mut(), derived.get_mut());
} |
I think there's a lot of red herrings here. The underlying thing to keep in mind is
Now, as you discovered, sometimes an Having aliasing |
Neither is the case. LLVM |
I'm going to close this -- |
See https://users.rust-lang.org/t/can-you-break-the-lift/58858 for the original discussion (it actually starts from the 12th post)
The original question takes a
&UnsafeCell<T>
and, supposing that nobody is borrowing the inner value, gets a mutable reference (&mut T
) to the inner value, then trasmute it to a&mut UnsafeCell<T>
, creating a&mut UnsafeCell<T>
that alias with another&UnsafeCell<T>
. Is this sound? Does this also mean you can transmute a&UnsafeCell<T>
to a&mut UnsafeCell<T>
(assuming no other reference to the inner value exist)?Related: jasoncarr0 also showed you can safely do something like this with
GhostCell
.Also related: rust-lang/rust#63787 since that's also caused by a
&UnsafeCell<T>
aliasing with a reference to itself, even though in that case it's a reference to the inner value. While that may be solved by storing a raw pointer insideRef
, it's not an actual possibility here.I feel like that either this is unsound or the rust aliasing model is fundamentally incompatible with LLVM's noalias.
The text was updated successfully, but these errors were encountered: