You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This lets us use the dereferenceable attribute of LLVM, which means "dereferenceable for the entire duration this function runs". That is quite useful for e.g. hoisting memory accesses out of a loop without having to figure out if some other operation deallocated x.
However, we have an exception to that rule: if x is a reference to UnsafeCell<T> (or a newtype around that), then the memory is allowed to be deallocated while the function runs. (The reference must still be dereferenceable when the function starts.) This was done to resolve rust-lang/rust#55005; the PR that manifested this change is rust-lang/rust#98017.
IMO this was absolutely required; without a change like this, Atomic*::compare_exchange cannot be used as a signal to another thread "you may now free this memory". We would need to provide raw pointer alternatives to even implement something like Arc. However @JakobDegen indicated they disagree so this is part 1 of the issue tracked here. (Though I will note that this will be hard to take back since it has been FCP'd and documented.)
Part 2 is the problem that there are still footguns: with a type like
structS{b:AtomicBool,i:AtomicUsize,}
if we have a method on &S that sets a flag to indicate "this can be deallocated", we still have UB. This is because there is padding, and the rules say only memory inside the UnsafeCell is allowed to be deallocated.
There are a bunch of options here. Just to list a few:
Accept the current rules and tell people to use raw pointers instead.
Follow Tree Borrows and just don't care about where in a type the UnsafeCell lives ever (Cc Stacked Borrows: How precise should UnsafeCell be tracked? #236). Even if we track UnsafeCell precisely for mutation, we could say that deallocation is allowed the moment T: !Freeze.
Somehow treat padding that is adjacent to an UnsafeCell as also being inside the UnsafeCell.
Generally, this is UB:
This lets us use the
dereferenceableattribute of LLVM, which means "dereferenceable for the entire duration this function runs". That is quite useful for e.g. hoisting memory accesses out of a loop without having to figure out if some other operation deallocatedx.However, we have an exception to that rule: if
xis a reference toUnsafeCell<T>(or a newtype around that), then the memory is allowed to be deallocated while the function runs. (The reference must still be dereferenceable when the function starts.) This was done to resolve rust-lang/rust#55005; the PR that manifested this change is rust-lang/rust#98017.IMO this was absolutely required; without a change like this,
Atomic*::compare_exchangecannot be used as a signal to another thread "you may now free this memory". We would need to provide raw pointer alternatives to even implement something likeArc. However @JakobDegen indicated they disagree so this is part 1 of the issue tracked here. (Though I will note that this will be hard to take back since it has been FCP'd and documented.)Part 2 is the problem that there are still footguns: with a type like
if we have a method on
&Sthat sets a flag to indicate "this can be deallocated", we still have UB. This is because there is padding, and the rules say only memory inside theUnsafeCellis allowed to be deallocated.There are a bunch of options here. Just to list a few:
UnsafeCelllives ever (Cc Stacked Borrows: How precise should UnsafeCell be tracked? #236). Even if we trackUnsafeCellprecisely for mutation, we could say that deallocation is allowed the momentT: !Freeze.UnsafeCellas also being inside theUnsafeCell.