mcpField
R
rust-unsafe

rust-unsafe

github.com/mohitmishra786开发269568 次安装18 周前更新
代码仓库

关于 rust-unsafe

rust-unsafe 帮助 Agent 编写、审查和分析 Rust unsafe 代码,讲解不变量、安全抽象、指针规则和审计检查。

主要功能

  1. 01五种 unsafe 操作能力
  2. 02原始指针安全规则
  3. 03基于 unsafe 的安全抽象
  4. 04transmute 与 UnsafeCell 指南
  5. 05unsafe 审计清单

适用场景

  1. 01审查 unsafe 代码块
  2. 02为原始指针设计安全封装
  3. 03检查 unsafe trait 实现
  4. 04判断是否需要使用 unsafe

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill rust-unsafe

安装后在 Claude Code 中输入/rust-unsafe确认已加载。

附带文件references/unsafe-patterns.md

详细介绍

Rust unsafe

用途

指导 Agent 编写、审查和分析 unsafe Rust:哪些操作需要 unsafe、如何编写安全抽象、审计模式、常见陷阱,以及何时使用 unsafe。

触发条件

  • “在 Rust 中何时需要使用 unsafe?”
  • “如何基于 unsafe 代码编写安全抽象?”
  • “如何审计 unsafe 代码块?”
  • “Rust 中原始指针有哪些规则?”
  • “transmute 的作用是什么,何时安全?”
  • “如何正确实现 UnsafeCell?”

工作流

1. unsafe 的五种超能力

unsafe 恰好提供了安全 Rust 中不可用的五种能力:

  1. 解引用原始指针(*const T、*mut T)
  2. 调用 unsafe 函数(包括 extern "C" 函数)
  3. 访问或修改可变静态变量
  4. 实现 unsafe trait(Send、Sync)
  5. 访问联合体字段

Rust 中的其他一切操作——包括内存分配、借用和闭包——即使在 unsafe 代码块中也遵循安全规则。

2. 原始指针
// Creating raw pointers (safe — no dereference yet)
let x = 42u32;
let ptr: *const u32 = &x;
let mut_ptr: *mut u32 = &mut some_val as *mut u32;

// Null pointer
let null: *const u32 = std::ptr::null();
let null_mut: *mut u32 = std::ptr::null_mut();

// Dereference (unsafe)
let val = unsafe { *ptr };

// Null check
if !ptr.is_null() {
    let val = unsafe { *ptr };
}

// Offset (safe to compute, unsafe to dereference)
let arr = [1u32, 2, 3, 4, 5];
let p = arr.as_ptr();
let third = unsafe { *p.add(2) };   // arr[2]
let also_third = unsafe { *p.offset(2) };

// Slice from raw parts
let slice: &[u32] = unsafe {
    std::slice::from_raw_parts(p, arr.len())
};

正确解引用原始指针的规则:

  • 指针必须非空
  • 指针必须满足 T 的对齐要求
  • 内存必须已初始化为 T
  • 不得违反别名规则(一个位置只能有一个 &mut)
  • 内存必须在引用的生命周期内有效
3. unsafe 函数和 trait
// Declare unsafe function (callers must uphold invariants)
/// # Safety
/// `ptr` must be non-null and aligned to `T`, and point to initialized data.
/// The caller must ensure no other mutable reference to the same location exists.
unsafe fn read_ptr<T>(ptr: *const T) -> T {
    ptr.read()  // ptr::read is unsafe
}

// Call unsafe function
let val = unsafe { read_ptr(some_ptr) };

// Unsafe trait — implementor must uphold safety invariants
unsafe trait MyUnsafeTrait {
    fn operation(&self);
}

// Implementing an unsafe trait is unsafe
unsafe impl MyUnsafeTrait for MyType {
    fn operation(&self) { /* must uphold the trait's invariants */ }
}

// Send and Sync
// Send: type can be moved to another thread
// Sync: type can be shared between threads (&T is Send)
unsafe impl Send for MyType {}
unsafe impl Sync for MyType {}
4. 基于 unsafe 编写安全抽象
// The golden rule: unsafe blocks should be small, isolated, and
// wrapped in a safe API that maintains the invariant

pub struct MyVec<T> {
    ptr: *mut T,
    len: usize,
    cap: usize,
}

impl<T> MyVec<T> {
    pub fn new() -> Self {
        MyVec { ptr: std::ptr::NonNull::dangling().as_ptr(), len: 0, cap: 0 }
    }

    // Safe public API
    pub fn get(&self, index: usize) -> Option<&T> {
        if index < self.len {
            // Safety: index < len guarantees ptr+index is in bounds and initialized
            Some(unsafe { &*self.ptr.add(index) })
        } else {
            None
        }
    }

    // # Safety comment documents the invariant
    pub fn push(&mut self, val: T) {
        if self.len == self.cap {
            self.grow();
        }
        // Safety: len < cap after grow(), so ptr+len is in bounds
        unsafe { self.ptr.add(self.len).write(val) };
        self.len += 1;
    }
}

// Implement Drop to clean up
impl<T> Drop for MyVec<T> {
    fn drop(&mut self) {
        // Safety: ptr was allocated with this layout, and all elements are initialized
        unsafe {
            std::ptr::drop_in_place(std::slice::from_raw_parts_mut(self.ptr, self.len));
            std::alloc::dealloc(self.ptr as *mut u8,
                std::alloc::Layout::array::<T>(self.cap).unwrap());
        }
    }
}
5. transmute
// transmute: reinterpret bits of one type as another
// Both types must have the same size

// Safe uses:
let x: u32 = 0x3f800000;
let f: f32 = unsafe { std::mem::transmute(x) };  // bits → float

// Transmute slice pointer (sound if types have same size/align)
let bytes: &[u8] = &[0x00, 0x00, 0x80, 0x3f];
let floats: &[f32] = unsafe {
    std::slice::from_raw_parts(bytes.as_ptr() as *const f32, 1)
};

// Prefer safe alternatives when available:
let f = f32::from_bits(x);         // instead of transmute for float bits
let n = u32::from_ne_bytes(bytes); // instead of transmute for byte arrays

transmute 常见陷阱:

  • 大小不匹配(会导致编译错误,但泛型类型需要特别检查)
  • 创建无效的枚举值
  • 创建生命周期不正确的引用
6. UnsafeCell — 内部可变性
use std::cell::UnsafeCell;

// UnsafeCell is the only way to mutate through a shared reference
struct MyCell<T> {
    value: UnsafeCell<T>,
}

impl<T: Copy> MyCell<T> {
    fn new(val: T) -> Self {
        MyCell { value: UnsafeCell::new(val) }
    }

    fn get(&self) -> T {
        // Safety: single-threaded, no concurrent mutation
        unsafe { *self.value.get() }
    }

    fn set(&self, val: T) {
        // Safety: single-threaded, no outstanding references
        unsafe { *self.value.get() = val }
    }
}
7. unsafe 审计检查清单

审查 unsafe 代码块时:

  • 是否有 // Safety: 注释说明不变量?
  • 原始指针是否非空?
  • 原始指针是否与目标类型正确对齐?
  • 内存是否已初始化?
  • 引用的生命周期是否有效?
  • 是否遵守别名规则(没有同时存在 & 和 &mut)?
  • 对于 extern "C":是否记录并验证了 C 端不变量?
  • 对于 Send/Sync 实现:是否确实保证了线程安全?
  • unsafe 代码块是否尽可能小?
  • 是否为 unsafe 代码编写了 Miri 测试?
8. 何时使用 unsafe
Before reaching for unsafe, check:
├── Does std have a safe API? (Vec, Box, Arc — usually yes)
├── Does a crate handle it? (memmap2, nix, windows-sys)
├── Can you restructure to avoid it?
└── Is the performance gain measured and significant?

Legitimate uses:
├── FFI to C libraries (extern "C")
├── OS-level APIs (syscalls, mmap, ioctl)
├── Performance-critical data structures (custom allocators, SoA)
├── Hardware access (embedded, drivers)
└── Implementing safe abstractions (the standard library itself)

有关 unsafe 模式和审计示例,请参阅 references/unsafe-patterns.md。

相关技能

  • 使用 skills/rust/rust-sanitizers-miri — Miri 是测试 unsafe 代码的必备工具
  • 在 FFI 场景中使用 unsafe 模式,请参阅 skills/rust/rust-ffi
  • 调试 unsafe 代码中的 panic,请参阅 skills/rust/rust-debugging
  • 在 unsafe 代码中处理别名和内存排序,请参阅 skills/low-level-programming/memory-model

评论

支持 Markdown