Skip to content

Commit b5f018f

Browse files
authored
Merge pull request #408 from Enselic/unbounded-lifetime-example
Expand unbounded lifetime example code and improve wording
2 parents 24b09b1 + 87f5694 commit b5f018f

File tree

1 file changed

+24
-16
lines changed

1 file changed

+24
-16
lines changed

src/unbounded-lifetimes.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Unbounded Lifetimes
22

33
Unsafe code can often end up producing references or lifetimes out of thin air.
4-
Such lifetimes come into the world as *unbounded*. The most common source of this
5-
is dereferencing a raw pointer, which produces a reference with an unbounded lifetime.
6-
Such a lifetime becomes as big as context demands. This is in fact more powerful
7-
than simply becoming `'static`, because for instance `&'static &'a T`
8-
will fail to typecheck, but the unbound lifetime will perfectly mold into
9-
`&'a &'a T` as needed. However for most intents and purposes, such an unbounded
10-
lifetime can be regarded as `'static`.
4+
Such lifetimes come into the world as *unbounded*. The most common source of
5+
this is taking a reference to a dereferenced raw pointer, which produces a
6+
reference with an unbounded lifetime. Such a lifetime becomes as big as context
7+
demands. This is in fact more powerful than simply becoming `'static`, because
8+
for instance `&'static &'a T` will fail to typecheck, but the unbound lifetime
9+
will perfectly mold into `&'a &'a T` as needed. However for most intents and
10+
purposes, such an unbounded lifetime can be regarded as `'static`.
1111

1212
Almost no reference is `'static`, so this is probably wrong. `transmute` and
1313
`transmute_copy` are the two other primary offenders. One should endeavor to
@@ -17,17 +17,25 @@ boundaries.
1717
Given a function, any output lifetimes that don't derive from inputs are
1818
unbounded. For instance:
1919

20-
<!-- ignore: simplified code -->
21-
```rust,ignore
22-
fn get_str<'a>() -> &'a str;
20+
<!-- no_run: This example exhibits undefined behavior. -->
21+
```rust,no_run
22+
fn get_str<'a>(s: *const String) -> &'a str {
23+
unsafe { &*s }
24+
}
25+
26+
fn main() {
27+
let soon_dropped = String::from("hello");
28+
let dangling = get_str(&soon_dropped);
29+
drop(soon_dropped);
30+
println!("Invalid str: {}", dangling); // Invalid str: gӚ_`
31+
}
2332
```
2433

25-
will produce an `&str` with an unbounded lifetime. The easiest way to avoid
26-
unbounded lifetimes is to use lifetime elision at the function boundary.
27-
If an output lifetime is elided, then it *must* be bounded by an input lifetime.
28-
Of course it might be bounded by the *wrong* lifetime, but this will usually
29-
just cause a compiler error, rather than allow memory safety to be trivially
30-
violated.
34+
The easiest way to avoid unbounded lifetimes is to use lifetime elision at the
35+
function boundary. If an output lifetime is elided, then it *must* be bounded by
36+
an input lifetime. Of course it might be bounded by the *wrong* lifetime, but
37+
this will usually just cause a compiler error, rather than allow memory safety
38+
to be trivially violated.
3139

3240
Within a function, bounding lifetimes is more error-prone. The safest and easiest
3341
way to bound a lifetime is to return it from a function with a bound lifetime.

0 commit comments

Comments
 (0)