CodeQL documentation

Access of a pointer after its lifetime has ended

ID: rust/access-after-lifetime-ended
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: medium
Tags:
   - reliability
   - security
   - external/cwe/cwe-825
Query suites:
   - rust-security-extended.qls
   - rust-security-and-quality.qls

Click to see the query in the CodeQL repository

Dereferencing a pointer after the lifetime of its target has ended causes undefined behavior. Memory may be corrupted, causing the program to crash or behave incorrectly, in some cases exposing the program to potential attacks.

Recommendation

When dereferencing a pointer in unsafe code, take care that the pointer is still valid at the time it is dereferenced. Code may need to be rearranged or changed to extend lifetimes. If possible, rewrite the code using safe Rust types to avoid this kind of problem altogether.

Example

In the following example, val is local to get_pointer so its lifetime ends when that function returns. However, a pointer to val is returned and dereferenced after that lifetime has ended, causing undefined behavior:

fn get_pointer() -> *const i64 {
	let val = 123;

	&val
} // lifetime of `val` ends here, the pointer becomes dangling

fn example() {
	let ptr = get_pointer();
	let dereferenced_ptr;

	// ...

	unsafe {
		dereferenced_ptr = *ptr; // BAD: dereferences `ptr` after the lifetime of `val` has ended
	}

	// ...
}

One way to fix this is to change the return type of the function from a pointer to a Box, which ensures that the value it points to remains on the heap for the lifetime of the Box itself. Note that there is no longer a need for an unsafe block as the code no longer handles pointers directly:

fn get_box() -> Box<i64> {
	let val = 123;

	Box::new(val) // copies `val` onto the heap, where it remains for the lifetime of the `Box`.
}

fn example() {
	let ptr = get_box();
	let dereferenced_ptr;

	// ...

	dereferenced_ptr = *ptr; // GOOD

	// ...
}

References

  • © GitHub, Inc.
  • Terms
  • Privacy