Reputation: 3852
let r = 42;
unsafe {
let p = &r as *const i32 as *mut i32;
*p += 1;
}
println!("{}", r);
Is the above code UB
? Is there a chance rustc
(while assuming r
is a &i32
) would optimize this in a way that will end up as UB
?
What about this ↓
let rc = Rc::new(42);
unsafe {
let p = &*rc as *const i32 as *mut i32;
*p += 1;
}
println!("{}", rc);
Rc is a single-threaded reference-counting pointer, therefore it's not thread safe.
Assuming the above is executed in a single thread, could it end up as UB
?
Upvotes: 0
Views: 316
Reputation: 10217
Both cases are definitely UB.
The main problem here is the fact that any changes to the value behind the shared reference are illegal, with the exception of UnsafeCell
internal values. The compiler can easily optimize away the change in first case and just substitute r
into println
call.
The second case is a bit more tricky, but it is based on the same fact. Note that the expression &*r
, where r
is of type Rc<T>
, is of type &T (playground):
use std::rc::Rc;
fn test<T>(r: Rc<T>) {
let _: () = &*r; // error: expected (), found &T
}
The trick is in the fact that Rc<T>
derefs to T
, so *r
has type T
.
So, it is again the immutable reference being treated as mutable.
Upvotes: 2