Hi!
I've recently realized that it is already possible to implement lazy_static!
(and more!) on stable Rust with a nice API without macros.
So, once_cell was created, which implements a single assignment cell-like type, which you can just use in a static context, without any strings attached.
See the docs for various examples: once_cell - Rust .
4 Likes
Looks interesting. Is there any proof/reasoning/argument that justifies the use of unsafe to show that it introduces no UB?
Is there any proof/reasoning/argument that justifies the use of unsafe to show that it introduces no UB?
There's definitely no formal proof. The informal reasoning is documented in the source code, and I would really appreciate a unsafe code review: Unsafe audit · Issue #1 · matklad/once_cell · GitHub .
The implementation is mostly based on lazycell
and lazy_static
, which is not as reassuring as it sounds, because both of them had/have soundness holes
indiv0:master
← matklad:sound
opened 02:33PM - 24 Nov 17 UTC
opened 09:18AM - 28 Jun 18 UTC
closed 05:29AM - 03 Aug 18 UTC
While normally only used within the `lazy_static` macro, the type and its fields… need to be public, at least for the old `macro_rules` macros. This poses both a safety (the fields are used in unsafe ways) and stability hazard (changing implementation details is *technically* breaking).
Because `Lazy::get` takes `&'static mut self`, it's hard to abuse (`static mut` itself is unsafe, so it doesn't really count here), but `Box::leak` does let you create a `&'static mut` at runtime, so you *could*, in theory, leak a `Lazy<T>`, trigger the `call_once` manually, then call `Lazy::get`, which will return an invalid reference to a `T` (since no actual initialization occurred).
To construct a `Lazy<T>` to initialize the static in the macro, you can use associated consts (since 1.20):
```rust
impl<T> Lazy<T> {
const INIT: Self = Lazy(None, ONCE_INIT);
}
```
This way, the fields can be made private (we should try a crater run if possible - cc @kennytm @Mark-Simulacrum - just to make sure nobody was using the `Lazy` type themselves).
2 Likes