# Allow moving out of mutable references with \`panic=abort\`

**URL:** <https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114>\
**Category:** Unsafe Code Guidelines\
**Created:** [January 4, 2025, 9:28pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114 "2025-01-04T21:28:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 4, 2025, 9:28pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/1 "2025-01-04T21:28:31Z")

</div>

Hello, the reason we can't move out of mutable references and then borrow checker controlling that it was moved back is unwinding. But when `panic=abort`, there can't be any unwinding. Can we then make it legal to move out of mutable references?

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [January 4, 2025, 10:10pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/2 "2025-01-04T22:10:37Z")

</div>

I thought so too, and got about 70% of the way through writing an `unsafe` kludge to let my panic handler steal the global `LineWriter` wrapping `stderr` from my main program, but then I realized I was wrong. It's still unsound (not just unsafe) to steal mutable access to something, even when there's no unwinding and no threads, because of _reentrancy_ effects. The panic handler could have interrupted execution _of the guts of the `LineWriter`_ and therefore cannot safely claim it even though the main program will never use it again.

I'm not sure this is exactly what you have in mind, though. Can you give a concrete example of the code you'd like to be able to write and presently can't?

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 4, 2025, 10:28pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/3 "2025-01-04T22:28:03Z")

</div>

I was thinking about non-aborting equivalent of this popular crate [take\_mut - Rust](https://docs.rs/take_mut/latest/take_mut/). It gives you `T` and on panic `catch_unwind` your closure, aborting the process

---

<div class="post-metadata">

**Author:** ![tczajka](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tczajka/32/8923_2.png) [@tczajka](https://internals.rust-lang.org/u/tczajka)\
**Post date:** [January 4, 2025, 10:35pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/4 "2025-01-04T22:35:41Z")

</div>

> [@zackw](#):
>
> Can you give a concrete example of the code you'd like to be able to write and presently can't?

Implement `mem::replace` using direct, safe code:

```rust
fn replace(dest: &mut String, src: String) -> String {
    let result = *dest;
    *dest = src;
    result
}

```

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [January 4, 2025, 10:39pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/5 "2025-01-04T22:39:22Z")

</div>

[Mentioned by Niko in this blog post.](https://smallcultfollowing.com/babysteps/blog/2018/11/10/after-nll-moving-from-borrowed-data-and-the-sentinel-pattern/#panic--abort-having-semantic-impact) The missing tweet was something like "Chanting in the distance: panic=abort having semantic impact" IIRC.

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 4, 2025, 10:50pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/6 "2025-01-04T22:50:13Z")

</div>

I also don't feel like config option changing semantics is "clean", but on the other hand... Entire ecosystems (embedded for example, or wasm frontends, etc) paying costs like that and more for the thing we are not even using? It is sad...

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 4, 2025, 11:17pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/7 "2025-01-04T23:17:16Z")

</div>

I have 2 notes on argument against this in that article:

> The idea of aborting the process is that, unlike unwinding, we are guaranteeing that there are no more possible observers for that hole in memory. Interestingly, in writing this article, I realized that aborting the process does not compose with some other unsafe abstractions you might want. Imagine, for example, that you had memory mapped a file on disk and were supplying an &mut reference into that file to safe code. Or, perhaps you were using shared memory between two processes, and had some kind of locked object in there – after locking, you might obtain an &mut into the memory of that object. Put another way, if the take\_mut crate is safe, that means that an &mut can never point to memory not ultimately “owned” by the current process. I am not sure if that’s a good decision for us to make – though perhaps the real answer is that we need to permit unsafe crates to be a bit more declarative about the conditions they require from other crates, as I talk a bit about in this older blog post on observational equivalence.

First is, to my knowledge, it is (probably) already unsound for other "entity" to read/write memory of Rust code. It is not only touching those theoretical scenarios like mmap, but a highly practical one: you can't touch memory of wasm from host function called back by rust running inside. At least wasmi and wasmtime are not allowing it by mutaby borrowing access to the memory. I saw some folks implemented logging with unsafe, but it is not passing miri. (I did it by passing values on stack, not sure what wasm\_bindgen is doing, they execute from browser so no one is probably preventing them from reading).

Secondly, it states

> and had some kind of locked object in there – after locking, you might obtain an &mut into the memory of that object.

When I have `&mut T` and something is not aliasing due to that locking, then when I move out of reference it is still locked. If process aborts, nobody unlocked anything. Won't they touch memory before unlock?

It is up to us to define what next - for example, we can say that abort causes those uninit bytes to freeze.

And, additionally, I don't think llvm terms can really apply between processes - those are mmap'ed files. If you want to use mmap today, inside 1 process, to, for example, create a circular buffer, then you are out of luck and need to use pointers and volatiles. I can't imagine `&mut T` into mmap file...

To sum up: this is not just "a hole in memory", but "a mutaby borrowed hole in memory".

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [January 6, 2025, 2:00am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/8 "2025-01-06T02:00:53Z")

</div>

Here's some idea: some sort of language construct that guaranteed that certain piece of code doesn't panic. Then, inside that you could temporarily move out of mutable references, without leaving a sentinel value.

Something like this:

```rust
fn replace(dest: &mut String, src: String) -> String {
    nopanic {
        let result = *dest;
        *dest = src;
    }

    result
}

```

---

<div class="post-metadata">

**Author:** ![tigregalis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tigregalis/32/12735_2.png) [@tigregalis](https://internals.rust-lang.org/u/tigregalis)\
**Post date:** [January 6, 2025, 4:56am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/9 "2025-01-06T04:56:13Z")

</div>

I think it would be really cool to have this `nopanic` guarantee, not just for this reason.

What's the most recent discussion on this?

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonbuchan/32/9390_2.png) [@simonbuchan](https://internals.rust-lang.org/u/simonbuchan)\
**Post date:** [January 6, 2025, 6:18am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/10 "2025-01-06T06:18:25Z")

</div>

Does rust provide any panicking guarantees about eg. basic arithmetic? I'm curious just how much you actually can portably guarantee on the hardware out there.

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [January 6, 2025, 7:28am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/11 "2025-01-06T07:28:39Z")

</div>

You can just be very conservative: each operation that _might_ potentially panic can't be called in a `nopanic { }` block at all. Gradually the allowed operations could be expanded, just like `const { .. }` works today.

The real trouble is that making a non-panicking function panic is a semver-compatible change, so inferring whether an existing function panics would be too brittle (just imagine that after a minor upgrade to a crate, your code could randomly fail to compile). So, for this feature to work right we need a language-level `nopanic fn` notation on functions, again just like `const fn`, to declare a guarantee that this function will continue to not panic as the crate evolves (adding `nopanic` to a function is not a breaking change, but removing it is). Then, only a `nopanic fn` could be called inside a `nopanic { .. }` block, and it's up to each crate (including the stdlib) to properly annotate their APIs.

To avoid the ecosystem churn, the best time to introduce such `nopanic fn` notation was before Rust 1.0; the second best time is today.

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 6, 2025, 7:41am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/12 "2025-01-06T07:41:36Z")

</div>

This is already discussed in context of effects. For example, const traits are being rewritten with them.

Note, that this topic is about unwinding, not panics.

---

<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:** [January 6, 2025, 7:42am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/13 "2025-01-06T07:42:16Z")

</div>

> [@Ddystopia](#):
>
> But when `panic=abort`

You can just still use [replace\_with\_or\_abort in replace\_with - Rust](https://docs.rs/replace_with/latest/replace_with/fn.replace_with_or_abort.html) and its panic handling will optimize out with `panic=abort`, no?

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 6, 2025, 8:10am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/14 "2025-01-06T08:10:11Z")

</div>

I personally just have custom aborting function (it is not trivial to abort in `no_std`), but why if borrow checker can do the work? Those abstractions are really unpleasant to work with tbh.

---

<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:** [January 6, 2025, 8:26am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/15 "2025-01-06T08:26:48Z")

</div>

> [@Ddystopia](#):
>
> it is not trivial to abort in `no_std`

Is it? panic-while-unwinding is an abort, so you can always do that, even in `no_std` [https://rust.godbolt.org/z/cGc7rn4hs](https://rust.godbolt.org/z/cGc7rn4hs)

(That's what `replace_with` uses to avoid needing `catch_unwind` the way `take_mut` does.)

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 6, 2025, 8:39am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/16 "2025-01-06T08:39:34Z")

</div>

Sometimes you don't have unwinding as an option, it is directly not supported at all.

That's part of the reason why I say this. Sometimes you just _can't_ unwind, there is not an option to unwind. Code will not compile without `panic="abort"` Yet still you pay for it.

---

<div class="post-metadata">

**Author:** ![sahnehaeubchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sahnehaeubchen/32/9709_2.png) [@sahnehaeubchen](https://internals.rust-lang.org/u/sahnehaeubchen)\
**Post date:** [January 6, 2025, 9:02am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/17 "2025-01-06T09:02:28Z")

</div>

What about a `nounwind` block that generates an abort landing pad?

I feel that changes to "normal" borrow checker behavior should be locally visible.

---

<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:** [January 7, 2025, 9:38pm UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/18 "2025-01-07T21:38:38Z")

</div>

The pattern to turn unwinds into aborts is even available as an unstable API:

> **[abort\_unwind in core::panic - Rust](https://doc.rust-lang.org/stable/core/panic/fn.abort_unwind.html)**
>
> Invokes a closure, aborting if the closure unwinds.

> [@Ddystopia](#):
>
> it is not trivial to abort in `no_std`

I'm slowly chipping away at that. There's `core::intrinsics::abort`, and I'm slowly working on [exposing abort in core](https://github.com/rust-lang/libs-team/issues/442), progress just got held up by life and git randomly deciding it was going to fail every `fetch` for some reason (And then eventually randomly fixing itself.)

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 11, 2025, 1:00am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/19 "2025-01-11T01:00:55Z")

</div>

I think I want to write a pre-rfc for this. How do you think libs should handle it? If they are moving out of references then if user has `panic=unwind` then it would be really bad ux to give "cannot move out" error from within that lib.

So libs should be able to specify it in their Cargo.toml or like that, ideally with ability to feature gate it.

If just in lib.rs, then maybe like

```rust
#![cfg_attr(not(feature="unwind"), /* declare that panics cannot unwind*/]

#[cfg(feature = "unwind")]
fn swap<T>(a: &mut T, b: &mut T) { ... }

```

And add `unwind` as default, so that power users will opt out of it, if they have `panic=abort`. That way rustc will bail the library if it uses something incompatible with unwind before declaring it.

Or maybe just `#[cfg(unwind)]`, but that way library author is responsible to not put incompatible code out of cfg.

```rust
#[cfg(unwind)]
fn swap<T>(a: &mut T, b: &mut T) { ... }

```

Additional thoughts:

1. It will not cause an ecosystem split, as it be mainly used in ecosystems that are already separated from "main stream" (examples: embedded, wasm) or feature gated. E.g: if you want this feature, disable unwinding - seems really reasonable to me.
2. I personally think that even for web servers that want to handle panics gracefully, they are already relying on auto scaling from orchestrators like kubernetes for zero downtime, a single instance aborting must be expected.
3. Multithreading is really brittle in terms of errors in threads, you can't soundly terminate any, while ipc is not that bad, especially with crates like this [crates.io: Rust Package Registry](https://crates.io/crates/iceoryx2) .

Alternatively, maybe effects can play some role in here? As far as I can see, they are not really going anywhere except for const stuff, and even async folks decided to go with `AsyncFn` instead of `async Fn`, a small step in the opposite direction. And even if eventually there will be an effect like this, migration should be easy, through the edition, so that "hack" (with a _bunch_ of benefits for _nearly everyone_) will not make it harder for a "proper" solution like an effect - it will do the opposite, show case their benefit to Rust.

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [January 11, 2025, 1:30am UTC](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114/20 "2025-01-11T01:30:44Z")

</div>

Idea: can we allow threads to abort on panic instead of unwind or abort the process, while absolutely isolating it? From the point of any code it should be observable like it has `loop {}`, in other words:

If thread captured 'static data, the we will end up with leaked mutexes, as there is no one to unlock them.

If thread captured non static data, then currently it is only possible with scope. Scope can just never end, assuring that data remain borrowed. Thread will no harm to `&` data, while no one will be able to observe bad `&mut` data.

Paradoxically, even if it is "leaking" the whole thing, it is not incompatible with unleakable or linear types, as Rust program can assume that thread just went in `loop {}` (or got _unlucky_ with scheduling) , while actually being terminated by os. The rest of the program can move on but with some resources being borrowed "until that loop ends" - by thread capturing `'static`, by `scope` never returning, by linear type (`JoinHandle`) "guarding" the thread and keeping borrowing resources until some message from the thread, that will never come.

[Next page](https://internals.rust-lang.org/t/allow-moving-out-of-mutable-references-with-panic-abort/22114.md?page=2)
