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
Note that the following examples are just illustrations and are not intended as full-fledged implementations. There are many details for your specific situation that may require alterations to fit your needs. These are intended to help you see different ways to approach your problem. It is recommended to read the documentation for the specific types in the standard library, the reference on [undefined behavior], the [Rustonomicon], and if you are having questions to reach out on one of the Rust forums such as the [Users Forum].
This is probably something you already know, but if possible it is best to avoid mutable global state. Of course this can be a little more awkward or difficult at times, particularly if you need to pass a mutable reference around between many functions.
60
+
61
+
### Atomics
62
+
63
+
The [atomic types][atomics] provide integers, pointers, and booleans that can be used in a `static` (without `mut`).
64
+
65
+
```rust,edition2024
66
+
# use std::sync::atomic::Ordering;
67
+
# use std::sync::atomic::AtomicU64;
68
+
69
+
// Chnage from this:
70
+
// static mut COUNTER: u64 = 0;
71
+
// to this:
72
+
static COUNTER: AtomicU64 = AtomicU64::new(0);
73
+
74
+
fn main() {
75
+
// Be sure to analyze your use case to determine the correct Ordering to use.
76
+
COUNTER.fetch_add(1, Ordering::Relaxed);
77
+
}
78
+
```
79
+
80
+
[atomics]: ../../std/sync/atomic/index.html
81
+
82
+
### Mutex or RwLock
83
+
84
+
When your type is more complex than an atomic, consider using a [`Mutex`] or [`RwLock`] to ensure proper access to the global value.
If you are using a `static mut` because you need to do some one-time initialization that can't be `const`, you can instead reach for [`OnceLock`] or [`LazyLock`] instead.
107
+
108
+
```rust,edition2024
109
+
# use std::sync::LazyLock;
110
+
#
111
+
# struct GlobalState;
112
+
#
113
+
# impl GlobalState {
114
+
# fn new() -> GlobalState {
115
+
# GlobalState
116
+
# }
117
+
# fn example(&self) {}
118
+
# }
119
+
120
+
// Instead of some temporary or uninitialized type like:
[`OnceLock`] is similar to [`LazyLock`], but can be used if you need to pass information into the constructor, which can work well with single initialization points (like `main`), or if the inputs are available wherever you access the global.
This example is similar to [`OnceLock`] in that it provides one-time initialization of a global, but it does not require `std` which is useful in a `no_std` context. Assuming your target supports atomics, then you can use an atomic to check for the initialization of the global. The pattern might look something like this:
panic!("already initialized, or concurrent initialization");
220
+
}
221
+
}
222
+
223
+
fn get_state() -> &'static GlobalState {
224
+
if STATE_INITIALIZED.load(Ordering::Acquire) != INITIALIZED {
225
+
panic!("not initialized");
226
+
} else {
227
+
// SAFETY: Mutable access is not possible after state has been initialized.
228
+
unsafe { &*&raw const STATE }
229
+
}
230
+
}
231
+
232
+
fn main() {
233
+
let args = parse_arguments();
234
+
let state = GlobalState::new(args.verbose);
235
+
set_global_state(state);
236
+
// ...
237
+
let state = get_state();
238
+
state.example();
239
+
}
240
+
```
241
+
242
+
This example assumes you can put some default value in the static before it is initialized (the const `default` constructor in this example). If that is not possible, consider using either [`MaybeUninit`], dynamic trait dispatch (with a dummy type that implements a trait), or some other approach to have a default placeholder.
In some cases you can continue to use `static mut`, but avoid creating references. For example, if you just need to pass [raw pointers] into a C library, don't create an intermediate reference. Instead you can use [raw borrow operators], like in the following example:
Just beware that you still need to uphold the aliasing constraints around mutable pointers. This may require some internal or external synchronization or proofs about how it is used across threads, interrupt handlers, and reentrancy.
[`UnsafeCell`] does not impl `Sync`, so it cannot be used in a `static`. You can create your own wrapper around [`UnsafeCell`] to add a `Sync` impl so that it can be used in a `static` to implement interior mutability. This approach can be useful if you have external locks or other guarantees that uphold the safety invariants required for mutable pointers.
286
+
287
+
Note that this is largely the same as the [raw pointers](#raw-pointers) example. The wrapper helps to emphasize how you are using the type, and focus on which safety requirements you should be careful of. But otherwise they are roughly the same.
// SAFETY: This value is only ever read in our interrupt handler,
320
+
// and interrupts are disabled, and we only use this in one thread.
321
+
(*state).value = value;
322
+
}
323
+
});
324
+
}
325
+
```
326
+
327
+
The standard library has a nightly-only (unstable) variant of [`UnsafeCell`] called [`SyncUnsafeCell`]. This example above shows a very simplified version of the standard library type, but would be used roughly the same way.
In some cases it may be safe to create a reference of a `static mut`. The whole point of the [`static_mut_refs`] lint is that this is very hard to do correctly! However, that's not to say it is *impossible*. If you have a situation where you can guarantee that the aliasing requirements are upheld, such as guaranteeing the static is narrowly scoped (only used in a small module or function), has some internal or external synchronization, accounts for interrupt handlers and reentrancy, etc., then taking a reference may be fine.
335
+
336
+
There are two approaches you can take for this. You can either allow the [`static_mut_refs`] lint (preferably as narrowly as you can), or convert raw pointers to a reference, as with `&mut *&raw mut MY_STATIC`.
337
+
338
+
<!-- TODO: Should we prefer one or the other here? -->
339
+
51
340
## Migration
52
341
53
342
There is no automatic migration to fix these references to `static mut`. To avoid undefined behavior you must rewrite your code to use a different approach as recommended in the [Alternatives](#alternatives) section.
0 commit comments