full-stack-skills/rust-skills

rust-unsafe-ffi

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, unwindin…

查看源码
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

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:

rust
#![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

rust
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.add only 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 or assume_init.
  • Prefer from_ne_bytes, pointer casts with checked layout, or explicit field conversion over transmute.
  • Do not use ManuallyDrop to 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 ordinary Unpin data 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:

rust
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::ffi C 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:

bash
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 test

Also 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 Send and Sync implementations 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.

来自同一仓库

更多 Skills

全部 Skills
full-stack-skills
社区

rust-api-design

Design Rust library APIs that follow the Rust API Guidelines — naming (C-CASE, C-CONV, C-GETTER), interop traits (C-COMMON-TRAITS, C-CONVERT, C-ITER, C-SERDE), predictability (C-INTUITIVE, C-CONST), flexibility (C-GENERIC, C-NEWTYPE, C-EXT), type safety (C-BOOL, C-NONZERO, C-WRAPPER, C-STR), dependability (C-PANIC, C-UNWRAP), debuggability (C-DEBUG), and future-proofing (C-SEALED, C-STRUCT-FIELD, C-NON-EXHAUSTIVE). Use when users design a public crate API, choose between generics/concrete/newtype, decide trait bounds, hide implementation, avoid breakage, or ask "what is idiomatic Rust API design"; hand semver and publish workflow to rust-semver, lint config to rust-style-clippy, and in-crate layout to rust-module-layout.

安装量
1
GitHub Stars
5
最近更新
9月19日
full-stack-skills
社区

rust-by-example

Show Rust patterns through short compilable examples — type conversions (From/Into/TryFrom/as/Deref), flow control (if let/while let/match/loop), functions and closures (Fn/FnMut/FnOnce, captures), modules (mod/use/pub/super/self), generics and traits (bounds/associated types/trait objects), error handling (?/Result/thiserror/anyhow), attributes (derive/cfg/inline/allow), unsafe (raw pointers/unions/ABI), procedural macros (derive/attribute/function-like), and inline asm. Use when users ask "how do I write X in Rust", need a concrete pattern with copy-pasteable code, or are migrating from Java/Python/Go/C++ and want the Rust equivalent; hand architecture decisions to rust-api-design/rust-workspace, std API selection to rust-stdlib, and async runtime to rust-concurrency.

安装量
1
GitHub Stars
5
最近更新
9月19日
full-stack-skills
社区

rust-cargo-build

Configure, operate, diagnose, and automate Cargo for Rust packages and workspaces. Cover manifests and targets, commands, dependency resolution and features, profiles, build scripts, configuration and environment variables, caches and build diagnostics, cross-compilation, registries, packaging, publishing, metadata, CI reproducibility, and stable-versus-nightly feature gates. Use for Cargo.toml, Cargo.lock, .cargo/config.toml, cargo build/check/run/tree/metadata/package/publish, resolver or feature problems, build output and performance, private registries, and beginner Cargo workflows. Route crate selection and supply-chain audits to rust-dependencies, workspace topology to rust-workspace, test design to rust-testing, documentation design to rust-documentation, lint policy to rust-style-clippy, and API compatibility decisions to rust-semver.

安装量
1
GitHub Stars
5
最近更新
9月19日
full-stack-skills
社区

rust-cli

Design, implement, test, and release production Rust command-line applications, including command contracts, subcommands, configuration precedence, stdin/stdout/stderr, exit codes, file safety, daemon IPC, terminal handling, packaging, and process-level tests. Use when users ask for a Rust CLI, command parser, clap integration, Unix-style pipelines, daemon clients, PTY/TUI behavior, shell completion, or CLI release engineering.

安装量
1
GitHub Stars
5
最近更新
9月19日