plugins/languages/rust/skills/unsafe/SKILL.md
Rust unsafe 代码规范 — unsafe 最小化、五种超能力(裸指针 / unsafe fn / static mut / unsafe impl / union)、`// SAFETY:` 注释强制、`# Safety` 文档、安全 API 封装、FFI / CString / CStr / extern "C"、MIRI 验证、bytemuck / OnceLock / LazyLock 安全替代、UB(未定义行为)排查。编写 unsafe 块、调用 C 库、实现底层数据结构、排查未定义行为时加载。触发短语:unsafe、裸指针、FFI、extern C、transmute、UB、undefined behavior、MIRI、static mut。
npx skillsauth add lazygophers/ccplugin rust-unsafeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
前置:rust-core、rust-memory。
unsafe { ... } 只包含必须 unsafe 的语句。// SAFETY: <为什么这里安全、调用者保证什么、维护什么不变量>。cargo +nightly miri test。// 1. 解引用裸指针
let p = &42 as *const i32;
// SAFETY: p 指向栈上有效 i32,作用域内未被释放
let v = unsafe { *p };
// 2. 调用 unsafe fn
// SAFETY: src/dst 各有至少 len 个元素,且区间不重叠
unsafe { std::ptr::copy_nonoverlapping(src, dst, len); }
// 3. 访问 / 修改 static mut(强烈不推荐)
static mut COUNTER: u64 = 0;
// SAFETY: 单线程访问,无数据竞争 —— 但建议改用 OnceLock / AtomicU64
// 4. 实现 unsafe trait
// SAFETY: 所有字段均 Send,无内部可变性陷阱
unsafe impl Send for MyType {}
// 5. 读取 union 字段
union FloatBits { f: f32, i: u32 }
let fb = FloatBits { f: 1.0 };
// SAFETY: f32 与 u32 同大小同对齐,IEEE 754 位重解释 well-defined
let bits = unsafe { fb.i };
/// 从原始部件构造 Vec。
///
/// # Safety
///
/// - `ptr` 必须由 `Vec::into_raw_parts` 获得;
/// - 分配器为全局分配器;
/// - `length <= capacity`;
/// - 前 `length` 个元素已初始化。
pub unsafe fn from_raw_parts<T>(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> {
// SAFETY: 调用者保证以上前置条件
unsafe { Vec::from_raw_parts(ptr, length, capacity) }
}
use std::ffi::{c_char, CStr, CString};
extern "C" {
fn strlen(s: *const c_char) -> usize;
}
pub fn safe_strlen(s: &CStr) -> usize {
// SAFETY: CStr 保证 nul-terminated;strlen 仅只读访问
unsafe { strlen(s.as_ptr()) }
}
#[unsafe(no_mangle)] // Edition 2024 起 no_mangle 需 unsafe 属性
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 { a + b }
注意 Edition 2024 起 #[no_mangle] / #[export_name] / #[link_section] 需写成 #[unsafe(...)]。
| unsafe 场景 | 安全替代 |
|------------|---------|
| static mut 全局 | OnceLock / LazyLock / AtomicXxx |
| transmute 字节重解释 | bytemuck::cast / from_ne_bytes |
| 手动分配 | Vec / Box / bumpalo |
| 共享可变 | Mutex / RwLock / channel |
| 越界访问 | slice.get |
| 字符串转换 | CString::new / CStr::from_bytes_with_nul |
use std::sync::OnceLock;
static CONFIG: OnceLock<Config> = OnceLock::new();
fn config() -> &'static Config { CONFIG.get_or_init(load_config) }
use bytemuck::{Pod, Zeroable};
#[derive(Copy, Clone, Pod, Zeroable)] #[repr(C)]
struct Color { r: u8, g: u8, b: u8, a: u8 }
let c: Color = bytemuck::cast([255u8, 0, 0, 255]);
rustup +nightly component add miri
cargo +nightly miri test
MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test # 文件 IO
CI step 模板:
- run: rustup toolchain install nightly --component miri
- run: cargo +nightly miri test --workspace
| AI 倾向 | 正确做法 |
|---------|---------|
| unsafe 提性能 | 先 benchmark 证明热点 |
| transmute 强转 | bytemuck / From/Into |
| static mut 共享 | OnceLock / AtomicXxx |
| 无 SAFETY 注释 | 必须写明前置条件 |
| FFI 直接暴露 | 封装为安全 API |
| 无 MIRI | CI 加 miri 步骤 |
unsafe 块前有 // SAFETY: 注释unsafe fn 有 # Safety 文档cargo +nightly miri test 通过#[unsafe(no_mangle)] 等已迁移CString / CStr 正确转换development
Go 数据库规范——GORM Model 命名 ModelXxx、表名单数、枚举 uint8 + 常量、索引 idx_ 前缀 + deleted_at leading column、禁 time.Time 统一 int64 unix、禁指针/nullable 字段、TEXT/BLOB/JSON 禁 default、AutoMigrate 禁改主键。设计 DB model、写 GORM tag、建索引、做 migration 审查时触发。
development
Go HTTP API 规范——响应始终 200 + body code 字段、路由 /api/* 全 POST 单段 <Action><Model>、中间件逐路由注册禁 Group(prefix,mw...)、handler 仅返回 (rsp,error)、认证走 header。设计 HTTP API、写路由/handler/中间件时触发。
development
Go 项目结构规范——三层架构(API → Impl → State)、全局状态模式、internal/ 私有包、cmd/ 仅 main.go、go.work 多模块、禁止 Repository 接口和 DI 容器、struct 公共字段开头全 omitempty、handler var rsp 顶声明、禁 legacy migration。设计项目骨架、新建目录、组织包、做架构评审时触发。
development
Go 命名规范——Id/Uid 字段(非 ID)、IsActive/HasMFA 布尔前缀、CreatedAt 时间字段、接收者统一用 p、包名全小写无下划线、泛型类型参数描述性命名、集合字段 xxx_list 禁 xxxs 复数、Enum 0 值 XxxNil 禁 Unknown、禁 Status 统一 State、Set/Update 语义区分。定义结构体字段、函数、变量、包、接收者名、泛型、枚举时触发。