rust-unsafe-ffi
Skill4 starsChanged 3 months agoApache-2.0View on GitHub
Master unsafe Rust, FFI, and foreign function interface programming. Use when writing unsafe Rust code with raw pointers, interfacing with C/C++ libraries, creating bindings with bindgen, implementing zero-cost abstractions, working with uninitialized memory, or understanding the safety/unsafety boundary.
We split this skill into the rules it gives an agent
7 rules. 0 are common, 4 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 56
Not checked for aliasing
- Distinctive: line 87
When panic occurs, stack is unwound - must ensure no leaked resources or half-initialized data:
- Very specific: line 110
Use std::panic::catch_unwind for fallible FFI:
- Distinctive: line 121
Always initialize before reading:
- Very specific: line 138
Never use std::mem::zeroed() for non-Copy types:
- Very specific: line 188
Run cargo build to generate bindings.
- Distinctive: line 249
When writing unsafe code:
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Rust Unsafe & FFI Programming
Comprehensive guide to unsafe Rust and Foreign Function Interface (FFI) programming based on The Rustonomicon, Unsafe Code Guidelines, and bindgen documentation.
When to Use This Skill
- Writing unsafe Rust code with raw pointers
- Interfacing with C/C++ libraries via FFI
- Creating Rust bindings to C/C++ libraries with bindgen
- Implementing zero-cost abstractions over unsafe code
- Working with uninitialized or untyped memory
- Understanding the boundary between safe and unsafe Rust
- Writing sound unsafe code that doesn't cause undefined behavior
Core References
- The Rustonomicon - The definitive guide to unsafe Rust
- Unsafe Code Guidelines - What unsafe code can and cannot do
- bindgen User Guide - Automatic FFI binding generation
Unsafe Rust Fundamentals
The Safety/Unsafety Boundary
Unsafe Rust exists because Rust's safety guarantees are static - they can't be satisfied for all possible programs. Unsafe code tells the compiler "I promise this is safe."
Unsafe operations (require unsafe block):
- Dereferencing raw pointers (
*const T,*mut T) - Calling unsafe functions or methods
- Implementing unsafe traits
- Accessing or modifying mutable static variables
- Writing inline assembly
Raw Pointers
Raw pointers bypass lifetime/borrowing checks:
let num = 5;
let raw_ptr: *const i32 = #
let mut mutable = 10;
let raw_mut_ptr: *mut i32 = &mut mutable;
unsafe {
println!("Value: {}", *raw_ptr);
*raw_mut_ptr = 20;
}Key differences from references:
- Can be null
- Not checked for aliasing
- Can point to invalid memory
- No lifetime tracking
Creating Safe Abstractions
Wrap unsafe code in safe APIs:
pub struct Vec<T> {
ptr: NonNull<T>,
len: usize,
capacity: usize,
}
impl<T> Vec<T> {
pub fn push(&mut self, value: T) {
if self.len == self.capacity {
self.reallocate();
}
unsafe {
std::ptr::write(self.ptr.as_ptr().add(self.len), value);
}
self.len += 1;
}
}Exception Safety (Panic Safety)
The Panic/Unwind Safety Problem
When panic occurs, stack is unwound - must ensure no leaked resources or half-initialized data:
struct Wrapper {
data: ManuallyDrop<String>,
}
impl Drop for Wrapper {
fn drop(&mut self) {
unsafe { ManuallyDrop::drop(&mut self.data) };
}
}Panic Safety Guarantees
| Level | Description |
| No guarantee | May leak resources or corrupt data |
| Leak safe | No undefined behavior, but resources may leak |
| Unwind safe | No leaks, no corruption |
| Exception safe | Full safety including noexcept semantics |
Use std::panic::catch_unwind for fallible FFI:
std::panic::catch_unwind(|| {
unsafe { some_ffi_call() }
})Working with Uninitialized Memory
MaybeUninit
Always initialize before reading:
use std::mem::MaybeUninit;
let mut data: MaybeUninit<i32> = MaybeUninit::uninit();
// ... write to data ...
let value = unsafe { data.assume_init() };For arrays of MaybeUninit:
let mut arr: [MaybeUninit<i32>; 10] = [MaybeUninit::uninit(); 10];
arr[0].write(42);Zeroing Memory
Never use std::mem::zeroed() for non-Copy types:
use std::mem::MaybeUninit;
let mut data: MaybeUninit<String> = MaybeUninit::uninit();
// zeroed() is undefined behavior for String!FFI (Foreign Function Interface)
Calling C Functions
use std::ffi::CString;
#[link(name = "c")]
extern "C" {
fn printf(format: *const libc::c_char) -> libc::c_int;
}
let msg = CString::new("Hello %s\n").unwrap();
unsafe {
printf(msg.as_ptr());
}Using bindgen for Automatic Bindings
Add to Cargo.toml:
[build-dependencies]
bindgen = "0.69"
[dependencies]
libc = "0.2"Create build.rs:
fn main() {
bindgen::builder()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings")
.write_to_file("src/bindings.rs")
.expect("Couldn't write bindings!");
}Run cargo build to generate bindings.
Common FFI Patterns
Passing Strings
let c_string = CString::new("rust").unwrap();
unsafe { some_c_function(c_string.as_ptr()) }
unsafe {
let ptr = receive_c_string();
let rust_string = CString::from_raw(ptr).into_string().unwrap();
}Error Handling Across FFI
#[repr(C)]
pub struct FfiResult {
pub success: bool,
pub error_code: i32,
pub data: *mut std::ffi::c_void,
}Data Layout
Size, Alignment, and Padding
#[repr(C)] // C-compatible layout
struct Data {
a: u8, // offset 0
_pad0: [u8; 3],
b: u32, // offset 4
c: u16, // offset 8
_pad1: [u8; 2],
} // size = 12
#[repr(packed)] // No padding
struct Packed {
a: u8,
b: u32,
c: u16,
} // size = 7Type Punning
union IntOrFloat {
int: u32,
float: f32,
}
let mut value = IntOrFloat { int: 42 };
let float_val = unsafe { value.float };Soundness Checklist
When writing unsafe code:
- All unsafe blocks have safety comments explaining why they're safe
- Raw pointers are never dereferenced outside unsafe blocks
- References are never created from invalid pointers
- Data races are prevented (use proper synchronization)
- Memory is properly initialized before reading
- Memory is not used after being freed
- Panic safety is considered for allocations
- FFI boundaries handle all error cases
Reference Map
references/ffi-basics.md- Raw pointers, unsafe blocks, safe abstractionsreferences/ffi-bindgen.md- Using bindgen for C/C++ bindingsreferences/memory-layout.md- Size, alignment, padding, type punningreferences/exception-safety.md- Panic safety, unwind guarantees
Key References
- The Rustonomicon - Full unsafe Rust guide
- Unsafe Code Guidelines - Reference
- bindgen Book - FFI bindings
- libc crate - Unix/POSIX bindings
- std::ffi - FFI utilities
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- full-stack-skills/rust-skills★ 8same name
- jscott3201/yet-more-skills★ 4same name
- Lu1sDV/skillsmd★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository80 other files it gives its agents.
- a11y-accessibility-designSkill
- agentic-ui-patternsSkill
- ai-native-ui-designSkill
- ai-ui-anti-patternsSkill
- ai-ui-heuristicsSkill
- calm-technology-uiSkill
- conversion-growth-designSkill
- cross-platform-designSkill
- dark-mode-designSkill
- data-visualizationSkill
- design-systemsSkill
- design-thinking-processSkill
- error-empty-statesSkill
- ethical-design-patternsSkill
- form-uxSkill
- information-architectureSkill
- interaction-design-patternsSkill
- internationalization-uiSkill
- mobile-touch-designSkill
- modal-classes-lifecycleSkill
- modal-container-imagesSkill
- modal-dicts-queuesSkill
- modal-endpointsSkill
- modal-fundamentalsSkill
- modal-gpu-computeSkill
- modal-networkingSkill
- modal-observabilitySkill
- modal-parallel-executionSkill
- modal-sandboxesSkill
- modal-scaling-performanceSkill
- modal-schedulingSkill
- modal-secretsSkill
- modal-serversSkill
- modal-storageSkill
- modal-web-servingSkill
- modal-workspace-adminSkill
- motion-design-principlesSkill
- notifications-permissionsSkill
- onboarding-uxSkill
- rust-api-designSkill
- rust-async-programmingSkill
- rust-cargo-masterySkill
- rust-cli-applicationsSkill
- rust-clippy-lintsSkill
- rust-closures-iteratorsSkill
- rust-compiler-internalsSkill
- rust-concurrencySkill
- rust-design-patternsSkill
- rust-editionsSkill
- rust-embeddedSkill
- rust-error-handlingSkill
- rust-game-developmentSkill
- rust-lifetimes-borrowingSkill
- rust-macrosSkill
- rust-performanceSkill
- rust-rustdocSkill
- rust-rustup-toolchainSkill
- rust-smart-pointersSkill
- rust-testing-benchmarkingSkill
- rust-type-systemSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

