# Static mutable references to ZSTs

**URL:** <https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330>\
**Category:** libs\
**Created:** [February 12, 2023, 8:16am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330 "2023-02-12T08:16:42Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![ds84182](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ds84182/32/12379_2.png) [@ds84182](https://internals.rust-lang.org/u/ds84182)\
**Post date:** [February 12, 2023, 8:16am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/1 "2023-02-12T08:16:42Z")

</div>

Context: [It should be possible to get a mutable reference to a ZST literal · Issue #103821 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/issues/103821)

It currently isn't possible to get a `'static` dangling ref to a ZST without resorting to `Box::leak` or `NonNull::dangling()`, which is unsafe. While it does work for mutable slices, the produced assembly for `&mut []` is less than ideal since it loads a pointer to the data section of the binary. ([Compiler Explorer](https://rust.godbolt.org/z/rPTT5ncn6))

Also, the `Box::leak` method does not work without `core::alloc`.

A possible solution is `std::mem::dangling`, defined as:

```rust
pub fn dangling<'a, T: 'a>(zst: T) -> &'a mut T {
  assert!(std::mem::size_of_val(&zst) == 0);
  unsafe { &mut *std::ptr::NonNull::dangling().as_mut() }
}

```

This may need a different solution for `str`, since going from `[u8]` -\> `str` with `std::str::from_utf8_mut` generates a lot of code. `&mut str` could impl `From<&mut [u8; 0]>`, for example.

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [February 12, 2023, 12:34pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/2 "2023-02-12T12:34:29Z")

</div>

> [@ds84182](#):
>
> It currently isn't possible to get a `'static` dangling ref to a ZST without resorting to `Box::leak` or `NonNull::dangling()`, which is unsafe.

Note that leaking heap memory with `Box::leak()` is not unsafe. But yes, by its very nature it requires heap allocation capabilities to work.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [February 12, 2023, 12:56pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/3 "2023-02-12T12:56:47Z")

</div>

What's the use for it?

Mutation of ZST doesn't do anything, so why should libstd have special support no-op code that tries to do this?

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [February 12, 2023, 2:07pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/4 "2023-02-12T14:07:18Z")

</div>

The code appears to be a missing `core::mem::forget(zst)` (or equivalent). You can't copy the value with a `Copy` bound and as written it will be dropped at the end, which makes the accessible value afterwards an invalid copy. The intended effect is to pretend such a value to have beeen ''written-to'' the returned memory location. An alternative would indeed be `ptr::write(_, zst)` which is another no-op that simply forgets the value.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [February 12, 2023, 3:17pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/5 "2023-02-12T15:17:50Z")

</div>

> [@ds84182](#):
>
> It currently isn't possible to get a `'static` dangling ref to a ZST without ... which is unsafe.

Creating a (reference to) an instance of an _arbitrary_ ZST has to stay unsafe, because the ZST might be some kind of significant token (e.g. providing unique access to mutable static state). Just because a type has no data bytes doesn't mean you should get to construct it if the language doesn't already allow that.

I agree it can and should be possible in the case where you _can_ construct an instance, though. (I just recently was disappointed to find out that I couldn't declare a `const` that was a mutable reference to a function item ZST, in order to make an easy "null value" of type `&mut dyn FnMut()`.)

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [February 12, 2023, 3:47pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/6 "2023-02-12T15:47:43Z")

</div>

Note the the signature as written _can be_ sound. A safe re-implementation is:

```rust
pub fn dangling<'a, T: 'a>(zst: T) -> &'a mut T {
    Box::leak(Box::new(zst))
}

```

However, one of the author's goals is for this operation to be available in no-std and without mention an allocator in the type system. The static code path is indeed pretty similar to the implementation above except for the drop omission mention in my other comment. It doesn't even allocate.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [February 12, 2023, 4:48pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/7 "2023-02-12T16:48:08Z")

</div>

Oops, I missed that the function took a parameter of type `T`, and was thinking of the case

```rust
fn dangling<'a, T: 'a>() -> &'a mut T

```

which would have the problem I described. Sorry for the noise.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 12, 2023, 7:30pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/8 "2023-02-12T19:30:08Z")

</div>

I don't think we'll get a runtime-checked version in std, but if/when it's possible to write `where const { size_of::<T> == 0 }` (or equivalent), then it seems reasonable to add.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 12, 2023, 8:12pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/9 "2023-02-12T20:12:27Z")

</div>

I had a PR for an API for "conjuring" ZSTs ([Add `mem::conjure_zst` for creating ZSTs out of nothing by scottmcm · Pull Request #95385 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/pull/95385)), but it didn't go anywhere. It could have had `conjure_zst_mut` and such too.

---

<div class="post-metadata">

**Author:** ![ds84182](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ds84182/32/12379_2.png) [@ds84182](https://internals.rust-lang.org/u/ds84182)\
**Post date:** [February 12, 2023, 8:31pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/10 "2023-02-12T20:31:47Z")

</div>

A potential problem with `conjure_zst` is that it allows creating ZSTs from outside crates. This may break API contracts in those crates.

For `dangling`, the ZST must be provided as an argument.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 12, 2023, 8:58pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/11 "2023-02-12T20:58:45Z")

</div>

> [@ds84182](#):
>
> A potential problem with `conjure_zst` is that it allows creating ZSTs from outside crates.

That's why it's `unsafe`, yes. And the doc-comment says this is _why_ it's `unsafe` 🙂

---

<div class="post-metadata">

**Author:** ![wishawa](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/wishawa/32/10034_2.png) [@wishawa](https://internals.rust-lang.org/u/wishawa)\
**Post date:** [February 14, 2023, 8:54pm UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/12 "2023-02-14T20:54:23Z")

</div>

A nice example of why conjuring ZST is unsafe is the token type of [GhostCell](https://docs.rs/ghost-cell/). Duplicating the token would allow mutable aliasing of the data.

But I agree that a way to leak an already-constructed ZST without Box would be useful.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [February 15, 2023, 10:02am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/13 "2023-02-15T10:02:16Z")

</div>

(NOT A CONTRIBUTION)

The first post should use size\_of instead of size\_of\_val; the compiler should then be able to optimize away the assert pretty easily.

> [@CAD97](#):
>
> I don't think we'll get a runtime-checked version in std, but if/when it's possible to write `where const { size_of::<T> == 0 }` (or equivalent), then it seems reasonable to add.

Seems like a strange requirement to me.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 15, 2023, 10:22am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/14 "2023-02-15T10:22:31Z")

</div>

I would want to put the ZST requirement in the signature such that it can be made to always succeed, rather than panicking for non-ZST. `Box::leak` works fine for all types; the point of a new way of doing it is that it can work without alloc, but only for ZST.

I don't think we have any publicly exposed and stable functionality which panics based on ZST or non-ZST (though I could just be forgetting some); rather, there's a significant amount of effort to ensure everything _doesn't_ break for ZST. The closest is the unstable `slice::array_chunks` which panics if the const `N` is 0, but there's documented intent to make that into a compile error before stabilization. To me, the static information of ZST-ness falls into that same category.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [February 15, 2023, 11:55am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/15 "2023-02-15T11:55:35Z")

</div>

(NOT A CONTRIBUTION)

I don't think array\_chunks should be blocked on that either.

The Rust standard library has plenty of APIs that document that they can panic if called with invalid arguments, because the type system can't easily express the constraint. In this case (and the array chunks case), it seems like a much more trivial burden to put on users to ensure their programs don't panic than in many others, such as bounds checking. I don't think useful APIs (here I am thinking more of array\_chunks than this API) should be blocked on an language feature that hasn't even been properly designed yet unless the lack of that feature has a clear, major negative impact on usability.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 16, 2023, 11:56am UTC](https://internals.rust-lang.org/t/static-mutable-references-to-zsts/18330/16 "2023-05-16T11:56:07Z")

</div>

Closed on May 16, 2023, 11:56am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
