一键导入
rust-unsafe
Unsafe code and FFI expert covering raw pointers (*mut, *const), FFI patterns, transmute, union,
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Unsafe code and FFI expert covering raw pointers (*mut, *const), FFI patterns, transmute, union,
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Actor model expert covering message passing, state isolation, supervision trees, deadlock prevention, fault tolerance, Actix framework, and Erlang-style concurrency patterns.
Rust anti-patterns and common mistakes expert. Handles code review issues with clone abuse, unwrap in production, String misuse, index loops, and refactoring guidance.
Advanced async patterns expert covering Stream implementation, zero-copy buffers, tokio::spawn lifetimes, plugin system scheduling, tonic streaming, and async lifetime management.
Advanced async patterns expert. Handles Stream processing, backpressure control, select/join operations, cancellation, Future trait implementation, and async runtime optimization.
Authentication and authorization expert covering JWT, API keys, OAuth, RBAC, password hashing, distributed token storage, and session management patterns.
Caching and distributed storage expert covering Redis, connection pools, TTL strategies, cache patterns (Cache-Aside, Write-Through), invalidation, and performance optimization.
| name | rust-unsafe |
| description | Unsafe code and FFI expert covering raw pointers (*mut, *const), FFI patterns, transmute, union, |
| metadata | {"triggers":["unsafe","raw pointer","FFI","extern","transmute","union","repr(C)","MaybeUninit","NonNull","SAFETY comment","soundness","undefined behavior","UB"]} |
| Use Case | Example | Justified? |
|---|---|---|
| FFI calls to C | extern "C" { fn libc_malloc(size: usize) -> *mut c_void; } | ✅ Yes |
| Low-level abstractions | Internal implementation of Vec, Arc | ✅ Yes |
| Performance optimization (measured) | Hot path with proven bottleneck | ⚠️ Verify first |
| Escaping borrow checker | Don't know why you need it | ❌ No |
Every unsafe block must include a SAFETY comment:
// SAFETY: ptr must be non-null and properly aligned.
// This function is only called after a null check.
unsafe { *ptr = value; }
/// # Safety
///
/// * `ptr` must be properly aligned and not null
/// * `ptr` must point to initialized memory of type T
/// * The memory must not be accessed after this function returns
pub unsafe fn write(ptr: *mut T, value: &T) { ... }
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
extern "C" {
fn c_function(s: *const c_char) -> i32;
}
// ✅ Safe wrapper
pub fn safe_c_function(s: &str) -> Result<i32, Box<dyn Error>> {
let c_str = CString::new(s)?;
// SAFETY: c_str is a valid null-terminated string created from Rust data.
// The pointer is valid for the duration of this call.
let result = unsafe { c_function(c_str.as_ptr()) };
Ok(result)
}
use std::ptr::NonNull;
struct Buffer {
ptr: NonNull<u8>,
len: usize,
}
impl Buffer {
pub fn write(&mut self, index: usize, value: u8) -> Result<(), String> {
if index >= self.len {
return Err("index out of bounds".to_string());
}
// SAFETY: We've checked index is within bounds.
// ptr is NonNull and points to valid memory.
unsafe {
self.ptr.as_ptr().add(index).write(value);
}
Ok(())
}
}
use std::mem::MaybeUninit;
// ✅ Safe uninitialized memory handling
fn create_buffer(size: usize) -> Vec<u8> {
let mut buffer: Vec<MaybeUninit<u8>> = Vec::with_capacity(size);
for i in 0..size {
buffer.push(MaybeUninit::new(0));
}
// SAFETY: All elements have been initialized to 0.
unsafe { std::mem::transmute(buffer) }
}
// ❌ Avoid: deprecated pattern
fn bad_buffer(size: usize) -> Vec<u8> {
let mut v = Vec::with_capacity(size);
unsafe { v.set_len(size); } // UB if not initialized!
v
}
#[repr(C)]
pub struct Point {
pub x: f64,
pub y: f64,
}
#[repr(C)]
pub enum Status {
Success = 0,
Error = 1,
}
// SAFETY: Layout matches C struct exactly
extern "C" {
fn process_point(p: *const Point) -> Status;
}
| Rule | Description |
|---|---|
| G-01 | Don't use unsafe to escape compiler safety checks |
| G-02 | Don't blindly use unsafe for performance |
| G-03 | Don't create "Unsafe" aliases for types/methods |
| Rule | Description |
|---|---|
| M-01 | Choose appropriate memory layout for struct/tuple/enum |
| M-02 | Don't modify memory variables of other processes |
| M-03 | Don't let String/Vec auto-deallocate memory from other processes |
| M-04 | Prefer reentrant versions of C-API or syscalls |
| M-05 | Use third-party crates for bit fields |
| M-06 | Use MaybeUninit<T> for uninitialized memory |
| Rule | Description |
|---|---|
| P-01 | Don't share raw pointers across threads |
| P-02 | Prefer NonNull<T> over *mut T |
| P-03 | Use PhantomData<T> to mark variance and ownership |
| P-04 | Don't dereference pointers cast to misaligned types |
| P-05 | Don't manually convert immutable pointers to mutable |
| P-06 | Use ptr::cast instead of as for pointer casts |
| Rule | Description |
|---|---|
| U-01 | Avoid unions except for C interop |
| U-02 | Don't use union variants with different lifetimes |
| Rule | Description |
|---|---|
| F-01 | Avoid passing strings directly to C |
| F-02 | Carefully read std::ffi types documentation |
| F-03 | Implement Drop for wrapped C pointers |
| F-04 | Handle panics across FFI boundaries |
| F-05 | Use portable type aliases from std or libc |
| F-06 | Ensure C-ABI string compatibility |
| F-07 | Don't implement Drop for types passed to extern code |
| F-08 | Handle errors properly in FFI |
| F-09 | Use references instead of raw pointers in safe wrappers |
| F-10 | Exported functions must be thread-safe |
| F-11 | Be careful with references to repr(packed) fields |
| F-12 | Document invariant assumptions for C parameters |
| F-13 | Ensure consistent data layout for custom types |
| F-14 | FFI types should have stable layout |
| F-15 | Validate robustness of external values |
| F-16 | Separate data and code for C closures |
| F-17 | Use opaque types instead of c_void |
| F-18 | Avoid passing trait objects to C |
| Rule | Description |
|---|---|
| S-01 | Be aware of memory safety issues from panics |
| S-02 | Unsafe code authors must verify safety invariants |
| S-03 | Don't expose uninitialized memory in public APIs |
| S-04 | Avoid double-free from panics |
| S-05 | Consider safety when manually implementing Auto Traits |
| S-06 | Don't expose raw pointers in public APIs |
| S-07 | Provide safe alternatives for performance |
| S-08 | Returning mutable reference from immutable parameter is wrong |
| S-09 | Add SAFETY comment before each unsafe block |
| S-10 | Add Safety section to public unsafe function docs |
| S-11 | Use assert! instead of debug_assert! in unsafe functions |
| Rule | Description |
|---|---|
| I-01 | Ensure I/O safety when using raw handles |
Do I really need unsafe?
→ Can I use safe abstractions?
→ Is this for FFI? (justified)
→ Is this for measured performance? (profile first)
→ Am I fighting the borrow checker? (redesign instead)
For every unsafe block:
1. Document preconditions
2. Explain why they hold
3. Reference invariants maintained
For public unsafe functions:
1. Add /// # Safety section
2. List all requirements
3. Document consequences of violations
# Detect undefined behavior
cargo +nightly miri test
# Memory leak detection
valgrind ./target/release/program
# Data race detection
RUST_BACKTRACE=1 cargo test --features tsan
Raw unsafe code
↓
Safe private functions (validate inputs)
↓
Safe public API (no unsafe visible)
| Error | Fix |
|---|---|
| Null pointer dereference | Check for null before dereferencing |
| Use after free | Ensure lifetime validity |
| Data race | Add synchronization |
| Alignment violation | Use #[repr(C)], check alignment |
| Invalid bit pattern | Use MaybeUninit |
| Missing SAFETY comment | Add comment |
| Deprecated | Modern Alternative |
|---|---|
mem::uninitialized() | MaybeUninit<T> |
mem::zeroed() (for reference types) | MaybeUninit<T> |
| Raw pointer arithmetic | NonNull<T>, ptr::add |
CString::new().unwrap().as_ptr() | Store CString first |
static mut | AtomicT or Mutex |
| Manual extern declarations | bindgen |
| Direction | Tool |
|---|---|
| C → Rust | bindgen |
| Rust → C | cbindgen |
| Python | PyO3 |
| Node.js | napi-rs |
| C++ | cxx |
When reviewing unsafe code:
MaybeUninit# Check for undefined behavior
cargo +nightly miri test
# Run with address sanitizer
RUSTFLAGS="-Z sanitizer=address" cargo +nightly test
# Check FFI bindings
cargo check --features ffi
# Verify memory safety
valgrind --leak-check=full ./target/release/program
# Documentation check
cargo doc --no-deps --open
Symptom: Use-after-free, segfault
// ❌ Bad: pointer outlives data
fn bad() -> *const i32 {
let x = 42;
&x as *const i32 // Dangling!
}
// ✅ Good: proper lifetime management
fn good(x: &i32) -> *const i32 {
x as *const i32 // Lifetime tied to input
}
Symptom: Undefined behavior, random values
// ❌ Bad: reading uninitialized memory
let x: i32;
unsafe { println!("{}", x); } // UB!
// ✅ Good: use MaybeUninit
let mut x = MaybeUninit::<i32>::uninit();
x.write(42);
let x = unsafe { x.assume_init() }; // Safe
Symptom: FFI crashes, data corruption
// ❌ Bad: default repr with FFI
struct Point { x: f64, y: f64 }
extern "C" { fn use_point(p: Point); }
// ✅ Good: explicit C layout
#[repr(C)]
struct Point { x: f64, y: f64 }
extern "C" { fn use_point(p: Point); }