Background:
Rust was originally designed as a language with a priority on memory safety. However, in some tasks — for example, when working with FFI or low-level allocators — it is necessary to use raw pointers and manually manage dynamic memory. Such tasks are encountered in system programming and performance optimization. Therefore, it is important to know how Rust prevents leaks, dangling pointers, and use-after-free errors.
Problem:
Raw pointers (*const T, *mut T) are not integrated into Rust's ownership and borrowing system: they can point to invalid memory, be incorrectly released, or not released at all. Mistakes in their use can lead to UB (undefined behavior), crashes, security vulnerabilities, or memory leaks.
Solution:
Instead of raw pointers, it is recommended to use safe types — Box, Rc, Arc, and for temporary references — borrow references. However, if raw pointers are unavoidable (e.g., for working with a C API), all operations are wrapped in unsafe blocks, Drop is carefully managed, and crates like NonNull are used whenever possible. Another technique is RAII wrappers and minimizing the lifetime of pointers.
Example code:
fn allocate_in_heap() -> Box<i32> { Box::new(100) } // memory will be freed automatically // with raw pointer unsafe fn leak_memory() { let ptr = libc::malloc(4) as *mut i32; if !ptr.is_null() { *ptr = 42; // libc::free(ptr); // forgetting to free will cause a leak! } }
Key features:
Does Box guarantee automatic cleanup of all nested values when Box is deleted?
Yes, when a Box<T> is deleted, the destructor first calls cleanup on the wrapper itself, then recursively on all data nested within (up to elements of Vec or other Boxes within the structure T).
Can a raw pointer to a structure be safely passed through several functions without risking use-after-free?
No, a raw pointer does not carry information about the lifetime of the object. The compiler cannot check safety, so the responsibility lies entirely with the developer: if the object is freed, the raw pointer will be left pointing to null.
If we manually use free or drop_in_place, can Rust call Drop twice on the same address?
Yes, if after manual deallocation another Box/pointer that refers to the same block is left, then when the second instance is destroyed, Drop will be called again, causing UB. One should never manually free what is managed by Box, Vec, etc.
A programmer accepted a raw pointer from an external C-library, did not free it after use, or perf-node-dealloc mistakenly got the lifetime wrong.
Pros:
Cons:
A RAII wrapper with Drop is used, the pointer is encapsulated in a Box or NonNull, everything is safely destroyed at the end of the scope.
Pros:
Cons: