rust-unsafe-ffi
Skill8 starsChanged 43 days agoApache-2.0View on GitHub
Design, implement, audit, and test unsafe Rust and foreign-function boundaries, including raw pointers, validity and aliasing invariants, MaybeUninit, layout, Pin, manual Send and Sync, allocators, C ABI declarations, callbacks, ownership transfer, unwinding, and Edition 2024 unsafe syntax. Use when safe Rust cannot express the required memory or ABI operation; require minimal unsafe blocks, explicit safety contracts, safe wrappers, Miri where applicable, and real platform integration tests.
We split this skill into the rules it gives an agent
18 rules. 0 are common, 8 are distinctive, and 10 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
8
Distinctive
This author's own choices. Worth a look.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 9
Treat unsafe as a proof obligation.
- Very specific: line 13
Use this skill for raw pointers, NonNull, unsafe functions and traits, unions, MaybeUninit, ManuallyDrop, layout, pinning, allocators, …
- Very specific: line 41
Use # Safety documentation for unsafe public APIs and // SAFETY: comments at proof sites.
- Very specific: line 53
Use ptr.add only within the same allocated object or one-past it.
- Very specific: line 55
Use MaybeUninit<T> while values may be uninitialized, and track exactly which elements were initialized before drop or assume_init.
- Very specific: line 56
Prefer from_ne_bytes, pointer casts with checked layout, or explicit field conversion over transmute.
- Very specific: line 57
Do not use ManuallyDrop to hide ownership ambiguity or double-drop risk.
- Very specific: line 61
Use #[repr(C)] for C-compatible struct layout and explicit reprs for shared enums.
- Very specific: line 62
Use #[repr(transparent)] only when its documented field restrictions hold.
- Distinctive: line 63
Treat padding as potentially uninitialized.
- Distinctive: line 65
Prefer established projection helpers or structural pinning patterns over raw self-referential pointers.
- Very specific: line 89
Use std::ffi C types or generated bindings, not assumed Rust integer widths.
- Distinctive: line 109
Read Unsafe and FFI Reference for memory-type details.
- Distinctive: line 120
Do tests exercise null, empty, maximum, misaligned, error, callback, and shutdown paths?
- Distinctive: line 124
Document every caller and implementation safety obligation.
- Distinctive: line 125
Keep unsafe blocks minimal and safe wrappers impossible to misuse from safe Rust.
- Distinctive: line 126
Verify ABI types, layout, ownership, error, and unwinding behavior.
- Distinctive: line 127
Run Miri where applicable and real platform tests for the external boundary.
“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 and FFI
Treat unsafe as a proof obligation. An unsafe block permits specific operations; it does not relax validity, aliasing, initialization, lifetime, data-race, layout, or ABI requirements.
Scope and Routing
Use this skill for raw pointers, NonNull, unsafe functions and traits, unions, MaybeUninit, ManuallyDrop, layout, pinning, allocators, manual Send or Sync, C ABI bindings, callbacks, handles, and ownership transfer.
Route ordinary ownership design to rust-stable, concurrent architecture to rust-concurrency, UniFFI-generated multi-language bindings to rust-uniffi-building, general build scripts to rust-cargo-build, and review reporting to rust-code-review.
Workflow
1. Justify and isolate unsafe operations
Identify the operation safe Rust cannot express. Prefer an audited crate or standard-library abstraction when it preserves the required behavior. Keep unsafe blocks small and enable:
#![deny(unsafe_op_in_unsafe_fn)]An unsafe fn must still place each unsafe operation in an explicit unsafe {} block. Expose a safe wrapper only when it can establish and preserve every invariant internally.
2. Write the safety contract before code
Document:
- pointer provenance, non-nullness, alignment, and dereferenceable byte range;
- initialization and validity requirements for the pointee type;
- aliasing and mutation rules for the full access duration;
- lifetime and ownership transfer, including who destroys or frees values;
- thread-safety and reentrancy requirements;
- ABI, layout, calling convention, integer width, and error conventions;
- panic or foreign-exception behavior across the boundary.
Use # Safety documentation for unsafe public APIs and // SAFETY: comments at proof sites.
3. Implement raw-memory operations conservatively
pub unsafe fn read_i32(ptr: *const i32) -> i32 {
// SAFETY: The caller guarantees that ptr is aligned, initialized,
// dereferenceable for one i32, and not concurrently mutated.
unsafe { ptr.read() }
}- Use
ptr.addonly within the same allocated object or one-past it. - Distinguish aligned and unaligned reads; never create a reference to an unaligned packed field.
- Use
MaybeUninit<T>while values may be uninitialized, and track exactly which elements were initialized before drop orassume_init. - Prefer
from_ne_bytes, pointer casts with checked layout, or explicit field conversion overtransmute. - Do not use
ManuallyDropto hide ownership ambiguity or double-drop risk.
4. Define layout and pinning precisely
- Use
#[repr(C)]for C-compatible struct layout and explicit reprs for shared enums. - Use
#[repr(transparent)]only when its documented field restrictions hold. - Treat padding as potentially uninitialized; do not serialize a struct by copying its raw bytes.
Pin<P>protects the pointee only under the pinning contract. It does not make ordinaryUnpindata immovable and does not by itself make a self-reference sound.- Prefer established projection helpers or structural pinning patterns over raw self-referential pointers.
5. Build a narrow FFI boundary
Edition 2024 requires unsafe extern blocks and unsafe attributes where applicable:
use std::ffi::{c_char, CStr};
unsafe extern "C" {
fn foreign_name() -> *const c_char;
}
pub fn name() -> Option<String> {
// SAFETY: The foreign contract promises either null or a valid,
// NUL-terminated string that remains alive for this call.
let ptr = unsafe { foreign_name() };
(!ptr.is_null()).then(|| {
// SAFETY: Non-nullness and termination follow from the contract above.
unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
})
}- Use
std::ffiC types or generated bindings, not assumed Rust integer widths. - Convert nullable pointers, lengths, ownership, and error codes at one boundary.
- Prevent unwinding across a C ABI unless the selected ABI explicitly permits it; catch panics at callbacks when necessary.
- Make callback lifetime, thread, cancellation, and unregister behavior explicit.
- Pair allocation and deallocation in the same allocator domain.
6. Verify the proof
Run applicable gates:
cargo fmt --all --check
cargo check --workspace --all-targets --all-features
cargo test --workspace --all-targets --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo miri testAlso use sanitizers or Valgrind where supported, ABI layout assertions, C-side integration tests, multiple optimization levels, and every supported operating system and architecture. Miri does not execute arbitrary foreign code, so isolate or mock the external call while testing the Rust-side memory contract.
Read Unsafe and FFI Reference for memory-type details. Read Execution Scenarios for representative boundaries.
Review Checklist
- Is unsafe necessary, minimal, and locally justified?
- Does each safety contract cover validity, aliasing, lifetime, layout, and concurrency?
- Can a safe caller violate the wrapper's assumptions?
- Are partial initialization and failure cleanup correct?
- Are ownership and deallocation symmetric across FFI?
- Can panic or foreign unwinding cross the ABI boundary?
- Are manual
SendandSyncimplementations proven for every field and callback? - Do tests exercise null, empty, maximum, misaligned, error, callback, and shutdown paths?
Completion Criteria
- Document every caller and implementation safety obligation.
- Keep unsafe blocks minimal and safe wrappers impossible to misuse from safe Rust.
- Verify ABI types, layout, ownership, error, and unwinding behavior.
- Run Miri where applicable and real platform tests for the external boundary.
- Record any property that could not be verified locally.
Upstream Sources
Data Privacy
This skill does not collect, store, or transmit user data. Do not send proprietary headers, generated bindings, crash dumps, or memory contents to external services without authorization.
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- botirkhaltaev/botir-skills★ 4same 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 repository32 other files it gives its agents.
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-exploreSkill
- openspec-proposeSkill
- rust-api-designSkill
- rust-by-exampleSkill
- rust-cargo-buildSkill
- rust-cliSkill
- rust-code-reviewSkill
- rust-concurrencySkill
- rust-crate-discoverySkill
- rust-databaseSkill
- rust-dependenciesSkill
- rust-documentationSkill
- rust-embeddedSkill
- rust-http-clientSkill
- rust-java-migrationSkill
- rust-java-migration-testingSkill
- rust-lombok-macrosSkill
- rust-macrosSkill
- rust-module-layoutSkill
- rust-observabilitySkill
- rust-performanceSkill
- rust-semverSkill
- rust-stableSkill
- rust-stdlibSkill
- rust-style-clippySkill
- rust-testingSkill
- rust-uniffi-buildingSkill
- rust-web-securitySkill
- rust-webSkill
- rust-workspaceSkill
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.

