# Building Blocks for Safer C FFI
`safer_cffi` provides Rust primitives for replacing C libraries with memory-safe
Rust implementations while maintaining full ABI compatibility with the original
C headers.
* **[Pointer Trackers](#pointer-trackers)** — Manage the lifecycle of Rust
objects handed to C as opaque handles or raw pointers, preventing
use-after-free and double-borrow bugs.
* **[Struct Field Helpers](#struct-field-helpers)** — Safe wrappers for common
C struct field patterns (`*mut T`/`c_int` array pairs and `const char*`
strings).
**Tip:** Take a look at [`examples/`](examples/) for patterns and common use
cases.
## Pointer Trackers
Trackers manage the lifecycle of Rust objects that are handed to C code as
opaque handles or pointers. They ensure objects are only accessed when valid and
prevent concurrent mutable access.
Both trackers implement the `Tracker<T>` trait, which provides:
* `register(Box<T>)` → Key — stores the object, returns a key for C.
* `borrow_mut(key)` → `Tracked<T>` — exclusive access via a RAII guard.
* `reclaim(key)` → `Box<T>` — takes back ownership, removing from tracker.
### `OpaqueTracker<T>` (recommended)
Uses generational `Handle<T>` IDs. Prevents use-after-free via generation checks
and detects double-borrows.
```rust
static TRACKER: safer_cffi::OpaqueTracker<MyObj> = safer_cffi::OpaqueTracker::new();
#[unsafe(no_mangle)]
pub extern "C" fn create() -> Handle<MyObj> {
TRACKER.register(Box::new(MyObj::default())).unwrap_or_else(|_| Handle::null())
}
#[unsafe(no_mangle)]
pub extern "C" fn destroy(h: Handle<MyObj>) {
let _ = TRACKER.reclaim(h);
}
```
See [`examples/opaque_tracker/`](examples/opaque_tracker/) for a full example.
### `RawTracker<T>`
Uses raw memory addresses (`*mut T`) as keys. Use only when C code needs the
actual pointer value (e.g. for direct field access). Caveats:
* Cannot be used if C creates objects — all objects must originate from Rust.
* Does not prevent ABA problems: a freed and re-allocated address silently
resolves to the new object.
See [`examples/raw_tracker/`](examples/raw_tracker/) for a full example.
## Struct Field Helpers
### C Slices — `CBufPtr<T>` and `OwnedCBufPtr<T>`
Many C structs contain `(*mut T, L)` pairs representing dynamically-sized arrays
(where `L` is an integer length type such as `c_int` or `usize`). `CBufPtr` and
`OwnedCBufPtr` can be used in place of `*mut T` and provide safe handles for
access and manipulation.
* **`CBufPtr<T, A = LibcAlloc>`**: Unowned buffer pointer wrapper
(`#[repr(transparent)]` around `*mut T`). Does not deallocate on drop.
* `with_len(len)` → `&[T]` — shared slice view for any `len: L` where `L:
CBufLen`.
* `with_len_mut(len)` → `&mut [T]` — mutable slice view for any `len: L`
where `L: CBufLen` and `A = LibcAlloc`.
* `as_vec_mut(&mut len)` → `CVecRefMut<'_, T, L, A>` — mutable vector
handle for any `L: CBufLen` (when `A: Default`).
* `as_vec_mut_in(&mut len, alloc)` → `CVecRefMut<'_, T, L, A>` — mutable
vector handle with custom allocator instance.
* `as_vec_mut_with_cap(&mut len, &mut cap)` → `CVecRefMut<'_, T, L, A, C>`
— capacity-tracking mutable vector handle. The extra `cap: C` field lets
`push_back` reuse spare capacity and grow geometrically, saving
reallocations.
* `as_vec_mut_with_cap_in(&mut len, &mut cap, alloc)` → `CVecRefMut<'_, T,
L, A, C>` — capacity-tracking handle with a custom allocator instance.
* `clone_and_leak(&[T])` → `CBufPtr<T>` — create a new CBufPtr by cloning
an existing slice using `LibcAlloc`.
* `clone_and_leak_in(&[T], alloc)` → `CBufPtr<T, A>` — create a new
CBufPtr by cloning an existing slice using a custom allocator.
* `from_boxed_slice(Box<[T], A>)` → `CBufPtr<T, A>` — create a new CBufPtr
from a `Box<[T]>`, transferring ownership.
* **`OwnedCBufPtr<T: Copy, A: DropByPtrAllocator = LibcAlloc>`**: RAII-owning
buffer pointer wrapper (`#[repr(transparent)]` around `*mut T`).
Automatically deallocates the underlying heap memory when dropped using
`A::deallocate_by_ptr` (e.g. `libc::free`). Because `T: Copy` (which implies
`!Drop`), elements do not require individual destruction, allowing the
buffer to be freed without tracking length at drop time. Dereferences
(`Deref`/`DerefMut`) to `CBufPtr<T, A>`, providing access to all `CBufPtr`
methods.
* `null()` → `OwnedCBufPtr<T, A>` — create a null owned buffer pointer.
* `from_boxed_slice(Box<[T], A>)` → `OwnedCBufPtr<T, A>` — create a new
OwnedCBufPtr from a `Box<[T]>`, transferring ownership.
* `from_raw(raw)` → `OwnedCBufPtr<T, A>` (unsafe) — construct from a raw
pointer, transferring ownership.
* `clone_from_slice(&[T])` → `OwnedCBufPtr<T>` — create a new OwnedCBufPtr
by cloning an existing slice using `LibcAlloc`. In particular, this can
be used for `Clone` impls of structs with `OwnedCBufPtr` fields.
* `clone_from_slice_in(&[T], alloc)` → `OwnedCBufPtr<T, A>` — create a new
OwnedCBufPtr by cloning an existing slice using a custom allocator.
* `try_clone_from_slice[_in]` — fallible variants of the above that return
`Err(AllocError)` instead of panicking if allocation fails.
* `into_c_buf_ptr(self)` → `CBufPtr<T, A>` — extract inner `CBufPtr`
without deallocating.
* `into_raw(self)` → `*mut T` — extract raw pointer without deallocating.
* **`CVecRefMut<'a, T, L, A = LibcAlloc, C = L>`**: A borrowed mutable
"vec-like" struct. Implements `DerefMut` to `&mut [T]`. When constructed via
`as_vec_mut_with_cap[_in]`, it also borrows a capacity field of type `C`.
Additional methods:
* `push_back(T)` / `try_push_back(T)` — append an element. When capacity
is tracked, appends into spare capacity without reallocating and grows
geometrically once full; otherwise reallocates by one slot per push.
* `capacity()` → `Option<usize>` — the tracked capacity, if any.
* `clear()` — drop all elements, free the (full-capacity) allocation via
the allocator, and reset to null/0.
* `swap(&mut CVecRefMut)` — swap two handles (pointer, len, and capacity)
using the same allocator.
Usage example:
```rust
#[repr(C)]
struct MyStruct {
// Safety invariant: the length of this array is `item_len`.
items: OwnedCBufPtr<Item>,
item_len: c_int,
}
impl MyStruct {
fn items(&self) -> &[Item] {
// SAFETY: the length of `items` is `item_len`.
unsafe { self.items.with_len(self.item_len) }
}
fn items_mut(&mut self) -> &mut [Item] {
// SAFETY: the length of `items` is `item_len`.
unsafe { self.items.with_len_mut(self.item_len) }
}
fn items_vec_mut(&mut self) -> CVecRefMut<'_, Item, c_int> {
// SAFETY: the length of `items` is `item_len`.
unsafe { self.items.as_vec_mut(&mut self.item_len) }
}
}
```
See [`examples/c_buf_ptr/`](examples/c_buf_ptr/) for a full example.
### C Strings — `CStrRef<'a>`
A `#[repr(transparent)]` wrapper around `NonNull<c_char>` that can be used as
`Option<CStrRef<'_>>` in FFI signatures where a nullable C string is expected.
Unlike `core::ffi::CStr`, it guarantees a thin pointer layout and ABI
compatibility with a C `const char*`.
Usage example:
```rust
use safer_cffi::CStrRef;
#[unsafe(no_mangle)]
pub extern "C" fn print_string(s: Option<CStrRef<'_>>) {
if let Some(c_str) = s {
// CStrRef can be safely converted to a &CStr
println!("Received: {}", c_str.to_c_str().to_string_lossy());
}
}
```
--------------------------------------------------------------------------------
This is not an officially supported Google product. This project is not eligible
for the
[Google Open Source Software Vulnerability Rewards Program](https://bughunters.google.com/open-source-security).