# Signal semantics for Rust

**URL:** <https://internals.rust-lang.org/t/signal-semantics-for-rust/24288>\
**Category:** Unsafe Code Guidelines\
**Created:** [May 9, 2026, 7:54pm UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288 "2026-05-09T19:54:59Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![azalea\_99](https://avatars.discourse-cdn.com/v4/letter/a/c89c15/32.png) [@azalea\_99](https://internals.rust-lang.org/u/azalea_99)\
**Post date:** [May 9, 2026, 7:54pm UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288/1 "2026-05-09T19:54:59Z")

</div>

Hello everyone!

Some operating systems have a concept of asynchronous signals -- an external events that can interrupt the control flow of a thread and cause it to execute a special function, called a _signal handler_. A control flow can be redirected into a signal handler from any point at which the signal is not blocked, which makes installing signal handlers very unsafe and requires caution while implementing a signal handler. C and C++ standards, as well as POSIX, specify what a signal is and what semantics they have, and what a signal handler can safely do.

I propose providing documentation what can a signal handler do in a Rust program, specifically:

- What functions from the standard library (`core` and maybe `std`) can be called from a signal handler?
- Allowed interactions with global objects. As far as I understand, a signal handler can only safely interact with immutable (without interior mutability) and atomic (`core::sync::atomic`) objects
- Safety of using the Rust formatting subsystem (`core::fmt`) -- can it be safe, what types from the standard library can be safely formatted

---

<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:** [May 10, 2026, 9:45am UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288/2 "2026-05-10T09:45:17Z")

</div>

Yeah, we should really document this more precisely.

On the opsem side, things behave largely like in C and C++ -- async signals (which also include HW interrupts) are considered basically "separate threads" with all the usual caveats (and data race UB) except that they are paired up with a "main" thread and have a special relationship with that thread (allowing the use of [`compiler_fence`](https://doc.rust-lang.org/nightly/std/sync/atomic/fn.compiler_fence.html) rather than `fence` when synchronizing with that thread).

Most of the rest of this is a libs question. There, the tl;dr is that `std` APIs are generally _not_ async-signal-safe.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 10, 2026, 10:49pm UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288/3 "2026-05-10T22:49:51Z")

</div>

What about unwinding?

---

<div class="post-metadata">

**Author:** ![user16251](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/user16251/32/10186_2.png) [@user16251](https://internals.rust-lang.org/u/user16251)\
**Post date:** [May 11, 2026, 10:44am UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288/4 "2026-05-11T10:44:18Z")

</div>

It's good to document this, but documentation without caveats will encourage people to use signal handlers. Linux users should be encouraged to use other, safer means to handle signals (`signalfd`).

---

<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:** [May 14, 2026, 12:13am UTC](https://internals.rust-lang.org/t/signal-semantics-for-rust/24288/5 "2026-05-14T00:13:21Z")

</div>

Unwinding runs destructors which can run arbitrary code. I'm not sure if low-level unwinding could work even if you didn't have any destructors - probably still wouldn't be guaranteed by the language because there's always a chance that it will need some incompatible OS API or lazily load and allocate unwind tables.

Panicking is totally incompatible with signal handlers, since it runs arbitrary code of panic handlers and `malloc`s `PanicHookInfo`.
