C.W.K.
Stream
Lesson 05 of 05 · published

No Dangling References

~10 min · borrowing, dangling, lifetimes, E0515

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

In C, returning a pointer to a local variable is a classic disaster: the local is destroyed when the function returns, and the caller is left holding a pointer to freed memory. Rust makes this impossible to compile.

The dangling reference, refused

If you try to return a reference to a value created inside a function, the borrow checker stops you: the value will be dropped at the function's end, so the reference would point at freed memory. Rust won't let that reference escape. The error names exactly what's wrong — the value doesn't live long enough.

The fix: return ownership, not a reference

If a function creates a value, it should return the value itself (transferring ownership), not a reference to it. The caller then owns it, and it lives as long as needed. Return references only when they borrow from something the caller already owns — like a parameter passed in.

A reference can never outlive what it points at. This is the second borrowing rule, enforced absolutely. Use-after-free isn't 'rare' in Rust — it's structurally impossible in safe code, proven for every reference at compile time.

This is where lifetimes come from

How does the compiler know a reference won't outlive its data? It tracks lifetimes — how long each reference stays valid. Usually it infers them silently. But when a function returns a reference derived from its inputs, you sometimes have to annotate them. That's the entire next track — and now you know exactly what problem it solves.

Code

The dangling reference Rust refuses to compile·rust
// This does NOT compile:
// fn dangle() -> &String {
//     let s = String::from("oops");
//     &s   // error[E0106]: missing lifetime / `s` does not live long enough
// }       // s is dropped here, so the returned reference would dangle

// The fix: return the value, transferring ownership.
fn no_dangle() -> String {
    let s = String::from("safe");
    s // ownership moves out to the caller — lives as long as needed
}

fn main() {
    let s = no_dangle();
    println!("{s}");
}

External links

Exercise

Write a function that tries to return a reference to a String it creates internally, and read the compiler error. Then fix it two ways: (1) return the owned String, and (2) take a reference parameter and return a slice of *that* instead. Why does version 2 compile?
Hint
Version 2 borrows from data the caller owns, which lives longer than the function call. A reference is fine as long as it points at something that outlives it.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.