# What is source of provenance for locals of async blocks?

**URL:** <https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532>\
**Category:** Unsafe Code Guidelines\
**Created:** [August 16, 2026, 3:24pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532 "2026-08-16T15:24:43Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [August 16, 2026, 3:24pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/1 "2026-08-16T15:24:43Z")

</div>

I was looking on conditions which allow a reference to escape its block syntactically, as in the example below.

```rust
// Subscription adds the reference to static BTreeMap<usize, &'static mut u32>
// new_event() increments all subscribed values

fn sync_test() {
    let mut events = 0;
    {
        let s = unsafe { Subscription::new(&mut events).unwrap() };
        new_event();
        new_event();

        // _ = { &events }; <-- would invalidate &mut, making line below UB

        new_event();
        s.unsubscribe();
    }
    assert_eq!(events, 3);
}

```

I get the synchronous example, but not why the same works for async:

```rust
/// SAFETY: poll the future to completion.
async unsafe fn async_test() {
    let mut events = 0;
    {
        let s = unsafe { Subscription::new(&mut events).unwrap() };
        new_event();
        
        yield_once().await; // forces to return Poll::Pending once
        // now we get control again, and it is another call...
        new_event();
        new_event();
        s.unsubscribe();
    }
    assert_eq!(events, 3);
}

```

One could think that provenance of `&mut events` has been renewed once we polled the async fn the second time. However, that reference could escape and be used while the future is inactive!

* * *

```rust
        let mut fut = std::pin::pin!(async {
            let mut events = 0;
            {
                let s = unsafe { Subscription::new(&mut events).unwrap() };
                new_event();
                yield_once().await;
                new_event();
                s.unsubscribe();
            }
            assert_eq!(events, 3);
        });

```

and wrapping code can call `new_event()` between `fut.poll`'s:

```rust
        let Poll::Pending = fut.as_mut().poll(cx) else { ... };
        _ = { &mut fut };
        // ^^^ `fut`'s mutable borrow (used to poll it) shall end
        
        new_event();
        let Poll::Ready(()) = fut.as_mut().poll(cx) else { ... };

```

So, there are no borrows of `fut`, but a part of its stack memory is modified. Miri accepts [it (the whole code included)](https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=3e6db9ff9bdf3ec3f2c7650fd01d00b2). What's the right model for the provenance here?

---

<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:** [August 16, 2026, 6:42pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/2 "2026-08-16T18:42:49Z")

</div>

The memory of async blocks is not subject to aliasing restrictions (currently via a special rule for `!Unpin` types, in the future via a wrapper type called `UnsafePinned`), so accesses to it "from outside" make use of the provenance the outside pointer/reference was originally created with, and _don't_ derive from, or conflict with, the `&mut` created for polling the async block.

---

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [August 17, 2026, 1:04pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/3 "2026-08-17T13:04:44Z")

</div>

Got it! So, projection of `&mut Pin<&mut impl !Unpin>` to `&mut impl !Unpin` is magic in pretty much the same way as `&Cell<impl Sized>` to `&mut impl Sized`?

---

<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:** [August 17, 2026, 2:52pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/4 "2026-08-17T14:52:00Z")

</div>

> [@ProgramCrafter](#):
>
> projection of `&mut Pin<&mut impl !Unpin>` to `&mut impl !Unpin` is magic

No, currently, `&mut impl !Unpin` is magic, regardless of how it is obtained. But _in the future_, the magic will be in [`&mut UnsafePinned<T>`](https://doc.rust-lang.org/stable/std/pin/struct.UnsafePinned.html). In both cases, the projection doesn’t matter.

> [@ProgramCrafter](#):
>
> in pretty much the same way as `&Cell<impl Sized>` to `&mut impl Sized`?

There is no such magic. If you create an exclusive reference to the contents of a `Cell<T>`, the resulting `&mut T` reference will have the same aliasing rules as any other `&mut T`. `Cell`’s interior mutability depends on _never creating_ such references.

---

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [August 17, 2026, 4:31pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/5 "2026-08-17T16:31:34Z")

</div>

> [@kpreid](#):
>
> There is no such magic. If you create an exclusive reference to the contents of a `Cell<T>`, the resulting `&mut T` reference will have the same aliasing rules as any other `&mut T`. `Cell`’s interior mutability depends on _never creating_ such references.

Sorry, meant `UnsafeCell` here; the fact that `UnsafeCell::as_mut_unchecked` adds the write permission out of thin air.

I was about to say that `&mut impl !Unpin` gains a larger lifetime than the pinned reference it was constructed from (there was no `&mut fut` living long enough), thus the extra provenance is minted out of thin air, but then I got that provenance doesn't 1-to-1 correspond to lifetimes.

---

<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:** [August 17, 2026, 5:16pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/6 "2026-08-17T17:16:02Z")

</div>

> [@ProgramCrafter](#):
>
> Sorry, meant `UnsafeCell` here; the fact that `UnsafeCell::as_mut_unchecked` adds the write permission out of thin air.

The documentation used to be written this way, but that was a conservative choice in documentation and never how the compiler or abstract machine actually worked. As of the resolution of [Can a pointer obtained by casting `&UnsafeCell\<T\>` to `*mut T` be written to? · Issue #281 · rust-lang/unsafe-code-guidelines · GitHub](https://github.com/rust-lang/unsafe-code-guidelines/issues/281) and [allow accessing the contents of UnsafeCell without going through get- #159730](https://github.com/rust-lang/rust/pull/159730), it has been settled that the thing which `UnsafeCell` does is prevent `&UnsafeCell<T>` from implying that the memory is not writable; there is no special power in `UnsafeCell`’s _methods_.

---

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [August 17, 2026, 5:56pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/7 "2026-08-17T17:56:01Z")

</div>

That's interesting.

To verify.

```rust
struct Foo {
    a: core::pin::UnsafePinned<u8>,
    b: u8,
    c: core::cell::UnsafeCell<u8>,
}

```

`&Foo` has permissions

- shared read only: ~~a,~~ b
- shared read/write: a,c

and `&mut Foo` has permissions

- shared read/write: a
- exclusive read/write: b,c

Is that about right?

---

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [August 17, 2026, 6:01pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/8 "2026-08-17T18:01:18Z")

</div>

While we're at that, is padding readable? writable through `&T`?

It's obviously writable through `&mut T` as long as `std::mem::swap` does an untyped copy.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [August 17, 2026, 6:13pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/9 "2026-08-17T18:13:01Z")

</div>

There's nothing special about padding. Padding inside an `UnsafeCell` is writable, padding outside only readable.

---

<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:** [August 17, 2026, 6:23pm UTC](https://internals.rust-lang.org/t/what-is-source-of-provenance-for-locals-of-async-blocks/24532/10 "2026-08-17T18:23:22Z")

</div>

Yes, that’s right as far as I know.
