其他
Rust unsafe 代码内存安全验证:用…
当需要验证 Rust unsafe 代码、排查越界/释放后使用/未初始化读取/数据竞争等未定义行为时,使用 nightly sanitizer 和 Miri 进行运行时与解释器检测。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
Rust unsafe 代码内存安全验证特定
解决思路
- 安装 nightly 工具链:`rustup toolchain install nightly`。
- 为 nightly 添加 rust-src:`rustup component add rust-src --toolchain nightly`。
- 在 Linux/macOS 上运行 AddressSanitizer:`RUSTFLAGS="-Z sanitizer=address" cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu`。
- 在 Linux 上运行 ThreadSanitizer:`RUSTFLAGS="-Z sanitizer=thread" cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu`。
- 在 Linux 上运行 MemorySanitizer,并要求全量插桩构建:`RUSTFLAGS="-Z sanitizer=memory -Zsanitizer-memory-track-origins" cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu`。
- 运行 UndefinedBehaviorSanitizer:`RUSTFLAGS="-Z sanitizer=undefined" cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu`。
- 使用 `-Zbuild-std` 重新构建标准库并带上 sanitizer,否则结果可能不准确。
- stable 上想用 sanitizer 时,用 `cross` 配合预配置 sanitizer 的 Docker 镜像,或在 nightly Docker 容器内运行 `cargo test`。
- stable 上也可用更简单的 UB 检查替代:先 `cargo install cargo-sanitize`,再 `cargo sanitize address`。
- 解读 Rust 的 ASan 报告:读取 `ERROR: AddressSanitizer`、错误类型、READ/WRITE 大小与地址、线程,以及符号化调用栈和分配位置。
- 按 ASan 错误类型定位 Rust 原因:`heap-buffer-overflow` 多半是 unsafe 切片越界访问。
- 按 ASan 错误类型定位 Rust 原因:`use-after-free` 多半是 Vec 重新分配后继续使用 unsafe 指针。
- 按 ASan 错误类型定位 Rust 原因:`stack-use-after-return` 多半是返回了局部变量引用。
- 按 ASan 错误类型定位 Rust 原因:`heap-use-after-free` 多半是 drop 或 Box::from_raw 之后继续使用。
- 安装 Miri(需要 nightly):`rustup +nightly component add miri`。
- 用 Miri 运行测试:`cargo +nightly miri test`。
- 用 Miri 运行指定测试:`cargo +nightly miri test test_name`。
- 用 Miri 运行二进制:`cargo +nightly miri run`。
- 以严格 provenance/Stacked Borrows 模型运行 Miri:`MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test`。
- 关闭 Miri 隔离以允许文件 I/O、时钟、随机数:`MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test`。
- 用 Miri 检测悬垂指针使用,例如 Box::into_raw 后 Box::from_raw drop,再解引用原指针。
- 用 Miri 检测非法 enum discriminant,例如把越界 u8 transmute 成 enum。
- 用 Miri 检测未初始化内存读取,例如 MaybeUninit::uninit().assume_init()。
- 用 Miri 检测 Stacked Borrows 违规,例如存在共享引用时通过可变裸指针写入。
- 用 Miri 检测数据竞争:Miri 模拟顺序执行,并通过 Stacked Borrows 等方式发现线程间竞争。
- 运行 ThreadSanitizer 并限制测试线程数、截取前 50 行输出:`RUSTFLAGS="-Z sanitizer=thread" RUST_TEST_THREADS=8 cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu 2>&1 | head -50`。
- 解读 TSan 输出:关注 `WARNING: ThreadSanitizer: data race`、写/读大小与地址、线程 ID、互斥锁信息,以及写操作和前一次读操作的调用栈。
- 设置 MIRIFLAGS `-Zmiri-disable-isolation`:允许 I/O、时钟、随机性。
- 设置 MIRIFLAGS `-Zmiri-strict-provenance`:启用比 LLVM 更严格的指针 provenance 检查。
- 设置 MIRIFLAGS `-Zmiri-symbolic-alignment-check`:启用更严格的对齐检查。
- 设置 MIRIFLAGS `-Zmiri-check-number-validity`:检查浮点/整数有效性。
- 设置 MIRIFLAGS `-Zmiri-num-cpus=N`:模拟 N 个 CPU 以测试并发。
- 设置 MIRIFLAGS `-Zmiri-seed=N`:为随机调度设置种子。
- 设置 MIRIFLAGS `-Zmiri-ignore-leaks`:抑制内存泄漏错误。
- 设置 MIRIFLAGS `-Zmiri-tag-raw-pointers`:跟踪裸指针 provenance。
- CI 中集成 Miri:安装 nightly、添加 miri 组件、运行 `cargo +nightly miri test`,并设置 `MIRIFLAGS: "-Zmiri-disable-isolation"`。
- CI 中集成 ASan:添加 nightly 的 `rust-src`,设置 `RUSTFLAGS="-Z sanitizer=address"`,运行 `cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu`。
- 相关技能联动:需要 GDB/LLDB 调试 Rust panic 时用 `skills/rust/rust-debugging`;需要 C/C++ sanitizer 用法与对比时用 `skills/runtimes/sanitizers`;需要 unsafe Rust 模式与审查清单时用 `skills/rust/rust-unsafe`;需要生成触发 sanitizer 错误的输入时用 `skills/runtimes/fuzzing`。
适用边界 · 注意事项
- 不能使用 nightly,也不能使用 Docker、cross 或 cargo-sanitize 的 stable 原生环境,不适合直接运行这些 sanitizer 命令。
- 目标平台不在支持范围内时不适用:ThreadSanitizer/MemorySanitizer 需要 Linux,AddressSanitizer 需要 Linux 或 macOS;MemorySanitizer 还要求全量插桩构建。
- Miri 默认隔离环境不适合依赖真实文件 I/O、时钟、随机数或系统调用的测试,除非设置 `-Zmiri-disable-isolation` 或改用 sanitizer/其他测试方式。