Description
static mut
is almost impossible to use correctly, see rust-lang-nursery/lazy-static.rs#117 for an example in the widely-used lazy-static
.
You must be able to show that every borrow of the static mut
is not reentrant (as opposed to regular interior mutability, which only requires reentrance-freedom when accessing data), which is almost entirely impossible in real-world scenarios.
We have a chance at removing it from Rust2018 and force people to use a proper synchronization abstraction (e.g. lazy_static!
+ Mutex
), or in lieu of one, thread_local!
/ scoped_thread_local!
.
If they were using static mut
with custom synchronization logic, they should do this:
pub struct CustomSynchronizingAbstraction<T> {
/* UnsafeCell / Cell / RefCell / etc. around data, e.g. `T` */
}
// Promise that proper synchronization exists *around accesses*.
unsafe impl<T: Sync> Sync for CustomSynchronizingAbstraction<T> {}
And then use CustomSynchronizingAbstraction
with regular static
s, safely.
This matches the "soundness boundary" of Rust APIs, whereas static mut
is more like C.
cc @RalfJung @rust-lang/compiler @rust-lang/lang
2023-08 Note from triage, many years later: there's now https://doc.rust-lang.org/1.71.0/std/cell/struct.SyncUnsafeCell.html in the library, added by #95438, which can be used instead of static mut
. But static mut
is not even soft-deprecated currently.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Activity
Centril commentedon Aug 23, 2018
I don't know at all whether we should do this or not atm. But to make this decision I have an...
...Idea: We should do a crater run to scrutinize how many legitimate usages there are and how many ones there are that have UB.
nikomatsakis commentedon Aug 23, 2018
cc @rust-lang/wg-unsafe-code-guidelines -- we have this group just for this sort of thing =)
alercah commentedon Aug 23, 2018
I'm 100% behind getting rid of
static mut
. Any attempt to use it which isn't UB is replaceable with something else which is safe, likely aMutex
or something thread local. Or, per the original comment, a custom alternate type implementingSync
directly.joshtriplett commentedon Aug 23, 2018
We should clearly document the undefined behavior, but I don't think we should remove the ability to have (unsafe) global mutable locations directly, without any layer of indirection. That would make it more difficult to build certain types of lock-free synchronization, for instance.
eddyb commentedon Aug 23, 2018
@joshtriplett But you can always use
unsafe impl Sync
+static
?alercah commentedon Aug 23, 2018
Can you give an example of what you mean? You can't do much more with
static mut
than you could with a staticUnsafeCell
.RalfJung commentedon Aug 23, 2018
Yeah, and that's just as unsafe. So TBH I do not see the point.
eddyb commentedon Aug 23, 2018
@RalfJung No, it's not, and I've explained why. With
unsafe impl Sync
, you only have to prove the data accesses correct, but withstatic mut
, the references themselves can conflict.EDIT: Now if "references exist" cannot be UB, ever, then this is not a problem, but IIUC, they do.
Also, you can't use a
static mut
from safe code, only astatic
. If thestatic mut
is used correctly, why spread unsafety when you can wrap it in a sound API.alercah commentedon Aug 23, 2018
It's not actually different from an
UnsafeCell
if we replace each&var
withunsafe {&*var.get()}
, right? Then the aliasing rules would be the same; the difference is that with theUnsafeCell
you can still keep references to the cell itself?RalfJung commentedon Aug 23, 2018
@eddyb Ah okay I see -- that has nothing to with with
unsafe impl
tough and everything with&UnsafeCell
.I agree
&UnsafeCell
is safer thanstatic mut
.eddyb commentedon Aug 23, 2018
@RalfJung Okay I should make it clearer that the
unsafe impl
is for "custom synchronization abstraction". I'll go edit the issue description.RalfJung commentedon Aug 23, 2018
If we could weaken
static mut
to only give you raw pointers, that could help...... tough people would probably still turn them into references ASAP.
japaric commentedon Aug 23, 2018
How would they instantiate their custom type in stable Rust? User
cons fn
s are unstable and even if we do stabilizemin_const_fn
that doesn't include anything that has bounds so even with that your example won't compile on stable.To me this sounds like it would reduce what you can do in the 2018 edition. In the 2015 edition you can create
static mut
variables that contain primitive types but in the 2018 edition you can not do the equivalent unless I'm missing something like adding aRacyCell
type withconst
constructor tocore
. (Here I'm assuming that it's not certain whethermin_const_fn
will make it into the edition release).299 remaining items