Claude-skill-registry rust-unsafe

不安全代码与 FFI 专家。处理 unsafe, raw pointer, FFI, extern, transmute, *mut, *const, union, #[repr(C)], libc, MaybeUninit, NonNull, SAFETY comment, soundness, undefined behavior, UB, 安全抽象, 裸指针, 外部函数接口, 内存布局, 未定义行为

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/rust-unsafe" ~/.claude/skills/majiayu000-claude-skill-registry-rust-unsafe && rm -rf "$T"
manifest: skills/data/rust-unsafe/SKILL.md
source content

不安全代码与 FFI

核心问题

什么时候可以用 unsafe,怎么用才安全?

unsafe 是必要的,但必须谨慎使用。


何时可以用 Unsafe

使用场景示例是否正当
FFI 调用 C
extern "C" { fn libc_malloc(size: usize) -> *mut c_void; }
实现底层抽象
Vec
,
Arc
的内部实现
性能优化(已测量)热点代码测出瓶颈⚠️ 需验证
逃避借用检查不知道为什么要用

SAFETY 注释要求

每个 unsafe 块必须包含 SAFETY 注释:

// 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) { ... }

47 条 Unsafe 规则速查

通用原则 (3条)

规则说明
G-01不要用 unsafe 逃避编译器安全检查
G-02不要盲目为性能使用 unsafe
G-03不要为类型/方法创建名为 "Unsafe" 的别名

内存布局 (6条)

规则说明
M-01为 struct/tuple/enum 选择合适的内存布局
M-02不要修改其他进程的内存变量
M-03不要让 String/Vec 自动释放其他进程的内存
M-04优先使用 C-API 或 Syscalls 的可重入版本
M-05用第三方 crate 处理位域
M-06
MaybeUninit<T>
处理未初始化内存

原始指针 (6条)

规则说明
P-01不要跨线程共享原始指针
P-02优先使用
NonNull<T>
而非
*mut T
P-03
PhantomData<T>
标记方差和所有权
P-04不要解引用强制转换为对齐错误的类型
P-05不要手动将不可变指针转为可变指针
P-06
ptr::cast
而非
as
做指针转换

联合 (2条)

规则说明
U-01除 C 互操作外避免使用 union
U-02不要在不同生命周期使用 union 变体

FFI (18条)

规则说明
F-01避免直接向 C 传递字符串
F-02仔细阅读
std::ffi
类型的文档
F-03为包装的 C 指针实现 Drop
F-04处理跨越 FFI 边界的 panic
F-05使用
std
libc
的可移植类型别名
F-06确保 C-ABI 字符串兼容性
F-07不要为传递给外部代码的类型实现 Drop
F-08在 FFI 中正确处理错误
F-09安全包装中用引用而非原始指针
F-10导出函数必须线程安全
F-11小心
repr(packed)
字段的引用
F-12文档化 C 参数的不变式假设
F-13确保自定义类型的数据布局一致
F-14FFI 中的类型应有稳定布局
F-15验证外部值的鲁棒性
F-16分离 C 闭包的数据和代码
F-17用不透明类型而非
c_void
F-18避免向 C 传递 trait object

安全抽象 (11条)

规则说明
S-01注意 panic 带来的内存安全问题
S-02unsafe 代码作者必须验证安全不变量
S-03不要在公共 API 中暴露未初始化内存
S-04避免因 panic 导致的双重释放
S-05手动实现 Auto Traits 时考虑安全性
S-06不要在公共 API 中暴露原始指针
S-07为性能提供安全的替代方法
S-08从不可变参数返回可变引用是错误的
S-09在每个 unsafe 块前添加 SAFETY 注释
S-10为公共 unsafe 函数添加文档中的 Safety 节
S-11在 unsafe 函数中使用
assert!
而非
debug_assert!

I/O 安全 (1条)

规则说明
I-01使用原始句柄时确保 I/O 安全

常见错误与修复

错误修复
空指针解引用解引用前检查 null
使用后释放确保生命周期有效性
数据竞争添加同步
对齐违规使用
#[repr(C)]
,检查对齐
无效位模式使用
MaybeUninit
缺少 SAFETY 注释添加注释

废弃模式

废弃替代
mem::uninitialized()
MaybeUninit<T>
mem::zeroed()
(引用类型)
MaybeUninit<T>
原始指针运算
NonNull<T>
,
ptr::add
CString::new().unwrap().as_ptr()
先存储
CString
static mut
AtomicT
Mutex
手动 extern
bindgen

FFI 工具

方向工具
C → Rust
bindgen
Rust → C
cbindgen
Python
PyO3
Node.js
napi-rs

调试工具

# Miri 检测未定义行为
cargo +nightly install miri
cargo miri test

# 内存问题检测
cargo install valgrind
valgrind ./target/release/my_program

# 竞态条件检测
cargo install helgrind
helgrind ./target/release/my_program