Course contentsShow
← Rust
Lesson 1621 of 1,91014. System Integration and EcosystemFree lesson

Memory Ownership Transfer

You will design interfaces that explicitly transfer memory responsibility between Rust and C heaps.

In this lesson, you will learn how to explicitly hand off memory ownership across the Foreign Function Interface (FFI) boundary, ensuring Rust and C don't accidentally stomp on each other's allocations.

The Ownership Hand-off

When interacting with C, the most dangerous point of failure is "who cleans up the memory." Rust’s Box<T> expects to deallocate via the Rust allocator, but if a C library allocates memory (e.g., via malloc), Rust’s drop will trigger a double-free or a segmentation fault if it tries to free that memory using the wrong allocator. Conversely, if Rust creates an object and passes it to C, you must prevent Rust from dropping it while C still needs it.

Transferring from Rust to C

To pass ownership of a Rust-allocated object to C, you must "leak" the pointer, effectively telling Rust to stop tracking it.

// Rust: Create a boxed value
let data = Box::new(MyData::new());

// Convert the Box into a raw pointer
let raw_ptr = Box::into_raw(data);

// Now, C is responsible for calling a C-defined destructor 
// or returning the pointer to Rust for manual reclamation.
unsafe { c_library_consume(raw_ptr); }

Reclaiming Ownership from C

If a C library returns a heap-allocated pointer to Rust, you must "re-import" that pointer into Rust’s ownership system. Use Box::from_raw to create a Box that now owns the memory and will safely deallocate it when it goes out of scope.

// C returns a pointer to a struct
let raw_ptr: *mut MyData = unsafe { c_library_allocate() };

// Reclaim the pointer, making Rust responsible for the cleanup
let data = unsafe { Box::from_raw(raw_ptr) };

// When 'data' goes out of scope, Rust calls the destructor 
// using its allocator, which must match the C allocator used!

The Crucial Constraint

This pattern relies on the Allocator Contract. You can only use Box::from_raw on memory allocated by an allocator compatible with Rust’s global allocator. If the C library uses a custom heap or a different version of malloc, you must provide a matching extern "C" destructor function that invokes the correct free() from the C side, rather than relying on Rust's drop.

Key Takeaway: Memory transfer across FFI is a manual "handshake" where Box::into_raw abdicates Rust’s ownership and Box::from_raw reclaims it; ensure both sides agree on the same allocator to prevent memory corruption.