Merge pull request #408 from Enselic/unbounded-lifetime-example

Expand unbounded lifetime example code and improve wording
pull/411/head
Eric Huss 2 years ago committed by GitHub
commit b5f018fb59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,13 +1,13 @@
# Unbounded Lifetimes # Unbounded Lifetimes
Unsafe code can often end up producing references or lifetimes out of thin air. Unsafe code can often end up producing references or lifetimes out of thin air.
Such lifetimes come into the world as *unbounded*. The most common source of this Such lifetimes come into the world as *unbounded*. The most common source of
is dereferencing a raw pointer, which produces a reference with an unbounded lifetime. this is taking a reference to a dereferenced raw pointer, which produces a
Such a lifetime becomes as big as context demands. This is in fact more powerful reference with an unbounded lifetime. Such a lifetime becomes as big as context
than simply becoming `'static`, because for instance `&'static &'a T` demands. This is in fact more powerful than simply becoming `'static`, because
will fail to typecheck, but the unbound lifetime will perfectly mold into for instance `&'static &'a T` will fail to typecheck, but the unbound lifetime
`&'a &'a T` as needed. However for most intents and purposes, such an unbounded will perfectly mold into `&'a &'a T` as needed. However for most intents and
lifetime can be regarded as `'static`. purposes, such an unbounded lifetime can be regarded as `'static`.
Almost no reference is `'static`, so this is probably wrong. `transmute` and Almost no reference is `'static`, so this is probably wrong. `transmute` and
`transmute_copy` are the two other primary offenders. One should endeavor to `transmute_copy` are the two other primary offenders. One should endeavor to
@ -17,17 +17,25 @@ boundaries.
Given a function, any output lifetimes that don't derive from inputs are Given a function, any output lifetimes that don't derive from inputs are
unbounded. For instance: unbounded. For instance:
<!-- ignore: simplified code --> <!-- no_run: This example exhibits undefined behavior. -->
```rust,ignore ```rust,no_run
fn get_str<'a>() -> &'a str; fn get_str<'a>(s: *const String) -> &'a str {
unsafe { &*s }
}
fn main() {
let soon_dropped = String::from("hello");
let dangling = get_str(&soon_dropped);
drop(soon_dropped);
println!("Invalid str: {}", dangling); // Invalid str: gӚ_`
}
``` ```
will produce an `&str` with an unbounded lifetime. The easiest way to avoid The easiest way to avoid unbounded lifetimes is to use lifetime elision at the
unbounded lifetimes is to use lifetime elision at the function boundary. function boundary. If an output lifetime is elided, then it *must* be bounded by
If an output lifetime is elided, then it *must* be bounded by an input lifetime. an input lifetime. Of course it might be bounded by the *wrong* lifetime, but
Of course it might be bounded by the *wrong* lifetime, but this will usually this will usually just cause a compiler error, rather than allow memory safety
just cause a compiler error, rather than allow memory safety to be trivially to be trivially violated.
violated.
Within a function, bounding lifetimes is more error-prone. The safest and easiest Within a function, bounding lifetimes is more error-prone. The safest and easiest
way to bound a lifetime is to return it from a function with a bound lifetime. way to bound a lifetime is to return it from a function with a bound lifetime.

Loading…
Cancel
Save