2 ms·
Transmuting lifetimes is one of the operations explicitly allowed for the std::mem::transmute() function [0]; lifetimes are only there to help safe code, and th
by LegionMammal978 3y ago
Transmuting lifetimes is one of the operations explicitly allowed for the std::mem::transmute() function [0]; lifetimes are only there to help safe code, and they have no effect on language-level UB. In fact, the 'static reference will be valid until the caller otherwise invalidates it.
[0] https://doc.rust-lang.org/1.73.0/std/mem/fn.transmute.html#examples https://doc.rust-lang.org/1.73.0/std/mem/fn.transmute.html#e...
- kibwen 3y agoYou're allowed to extend lifetimes via transmute, but unsafe code must adhere to the invariants of references as laid out by the Rustonomicon: 1. A reference cannot outlive its referent 2. A mutable reference cannot be aliased https://doc.rust-lang.org/nomicon/references.html https://doc.rust-lang.org/nomicon/references.html Therefore, any use of transmute that extends a lifetime is UB if it causes the reference to outlive the referent. And because it's UB, the backend is going to assume the invariant holds universally and will optimize accordingly. The Nomicon also has a section on generating lifetimes via transmute, which it calls "unbounded lifetimes": https://doc.rust-lang.org/nomicon/unbounded-lifetimes.html https://doc.rust-lang.org/nomicon/unbounded-lifetimes.html
- LegionMammal978 3y ago> Therefore, any use of transmute that extends a lifetime is UB if it causes the reference to outlive the referent. By itself, a transmute of a currently-live reference cannot make it outlive its referent, in the sense used by the Rustonomicon. As it says later [0], a reference is alive until the point when it is last used, and no further. Thus, with unsafe code, the lifetime of a reference can extend past the point when it stops being alive. As a consequence, extending the lifetime can never cause UB by itself: only using the reference after it has been invalidated can cause language-level UB. Since language-level UB is based on liveness rather than lifetime, the compiler must assume that a reference passed to a function is valid even after it returns, up until the caller invalidates the reference by performing an operation incompatible with it remaining alive. [0] https://doc.rust-lang.org/nomicon/lifetimes.html#the-area-covered-by-a-lifetime https://doc.rust-lang.org/nomicon/lifetimes.html#the-area-co...
- dwattttt 3y ago> only using the reference after it has been invalidated can cause language-level UB. When a reference is 'used' is much broader than you might expect; https://github.com/rust-lang/rust/issues/52898 https://github.com/rust-lang/rust/issues/52898 is a SIGILL from merely creating a null reference, never 'using' it.
- skitter 3y agoThat's not about 'using' a reference, it's about constructing an invalid value – no different than doing transmute::<u32,char>(0x110000). See https://www.ralfj.de/blog/2020/07/15/unused-data.html https://www.ralfj.de/blog/2020/07/15/unused-data.html for an explanation why it's UB.
- dwattttt 3y agoThat's true, but the claim was "it's ok to extend the lifetime of a reference beyond its referent so long as you don't use it after its referent has ceased being live"; what definition of 'used' the compiler might rely on is relevant.