rust-sanitizers-miri

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust Sanitizers and Miri

Rust Sanitizers 和 Miri

Purpose

用途

Guide agents through runtime safety validation for Rust: ASan/TSan/MSan/UBSan via RUSTFLAGS, Miri for compile-time UB detection in unsafe code, and interpreting sanitizer reports.
指导开发者通过Rust进行运行时安全验证:通过RUSTFLAGS使用ASan/TSan/MSan/UBSan,使用Miri检测不安全代码中的编译期未定义行为,以及解读Sanitizer报告。

Triggers

触发场景

  • "How do I run AddressSanitizer on Rust code?"
  • "How do I use Miri to check my unsafe Rust?"
  • "How do I run ThreadSanitizer on a Rust program?"
  • "My unsafe Rust might have UB — how do I detect it?"
  • "How do I interpret a Rust ASan report?"
  • "Can I run Rust sanitizers on stable?"
  • "如何在Rust代码上运行AddressSanitizer?"
  • "如何使用Miri检查我的不安全Rust代码?"
  • "如何在Rust程序上运行ThreadSanitizer?"
  • "我的不安全Rust代码可能存在UB,该如何检测?"
  • "如何解读Rust ASan的输出报告?"
  • "能否在稳定版Rust中运行Sanitizers?"

Workflow

操作流程

1. Sanitizers in Rust (nightly required)

1. Rust中的Sanitizers(需使用nightly版本)

Rust sanitizers require nightly and a compatible platform:
bash
undefined
Rust Sanitizers需要nightly版本和兼容的平台:
bash
undefined

Install nightly

安装nightly版本

rustup toolchain install nightly rustup component add rust-src --toolchain nightly
rustup toolchain install nightly rustup component add rust-src --toolchain nightly

AddressSanitizer (Linux, macOS)

AddressSanitizer(Linux、macOS)

RUSTFLAGS="-Z sanitizer=address"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu
RUSTFLAGS="-Z sanitizer=address"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu

ThreadSanitizer (Linux)

ThreadSanitizer(Linux)

RUSTFLAGS="-Z sanitizer=thread"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu
RUSTFLAGS="-Z sanitizer=thread"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu

MemorySanitizer (Linux, requires all-instrumented build)

MemorySanitizer(Linux,需要全 instrumentation 构建)

RUSTFLAGS="-Z sanitizer=memory -Zsanitizer-memory-track-origins"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu
RUSTFLAGS="-Z sanitizer=memory -Zsanitizer-memory-track-origins"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu

UndefinedBehaviorSanitizer

UndefinedBehaviorSanitizer

RUSTFLAGS="-Z sanitizer=undefined"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu

`-Zbuild-std` rebuilds the standard library with the sanitizer, which is necessary for accurate results.
RUSTFLAGS="-Z sanitizer=undefined"
cargo +nightly test -Zbuild-std
--target x86_64-unknown-linux-gnu

`-Zbuild-std`会使用Sanitizer重新构建标准库,这是获得准确结果的必要步骤。

2. Stable sanitizer workaround

2. 稳定版Rust使用Sanitizer的替代方案

For stable Rust, use the
cross
tool with a Docker image that has sanitizers pre-configured, or run
cargo test
inside a Docker container with a nightly image.
Alternatively, for simpler UB checking without nightly:
bash
undefined
对于稳定版Rust,可以使用
cross
工具搭配预配置了Sanitizers的Docker镜像,或者在装有nightly版本的Docker容器中运行
cargo test
另外,若无需nightly版本进行简单的UB检查,可使用:
bash
undefined

cargo-sanitize (wrapper)

cargo-sanitize(封装工具)

cargo install cargo-sanitize cargo sanitize address
undefined
cargo install cargo-sanitize cargo sanitize address
undefined

3. Interpreting ASan output in Rust

3. 解读Rust中的ASan输出

==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000050
READ of size 4 at 0x602000000050 thread T0
    #0 0x401234 in myapp::module::function /src/main.rs:15
    #1 0x401567 in myapp::main /src/main.rs:42

0x602000000050 is located 0 bytes after a 40-byte region allocated at:
    #0 0x... in alloc::alloc::alloc ...
    #1 0x... in myapp::create_buffer /src/main.rs:10
Rust-specific patterns:
ASan errorLikely Rust cause
heap-buffer-overflow
unsafe
slice access past bounds
use-after-free
unsafe
pointer use after Vec realloc
stack-use-after-return
Returning reference to local
heap-use-after-free
Use after
drop()
or
Box::from_raw
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000050
READ of size 4 at 0x602000000050 thread T0
    #0 0x401234 in myapp::module::function /src/main.rs:15
    #1 0x401567 in myapp::main /src/main.rs:42

0x602000000050 is located 0 bytes after a 40-byte region allocated at:
    #0 0x... in alloc::alloc::alloc ...
    #1 0x... in myapp::create_buffer /src/main.rs:10
Rust特有的错误模式:
ASan错误可能的Rust原因
heap-buffer-overflow
unsafe
切片越界访问
use-after-free
Vec重新分配后使用
unsafe
指针
stack-use-after-return
返回局部变量的引用
heap-use-after-free
drop()
Box::from_raw
后使用对象

4. Miri — interpreter for undefined behaviour

4. Miri — 未定义行为解释器

Miri interprets Rust MIR and detects UB that sanitizers might miss:
bash
undefined
Miri会解释Rust MIR并检测Sanitizers可能遗漏的UB:
bash
undefined

Install Miri (requires nightly)

安装Miri(需nightly版本)

rustup +nightly component add miri
rustup +nightly component add miri

Run tests under Miri

在Miri下运行测试

cargo +nightly miri test
cargo +nightly miri test

Run specific test

运行指定测试

cargo +nightly miri test test_name
cargo +nightly miri test test_name

Run a binary under Miri

在Miri下运行二进制程序

cargo +nightly miri run
cargo +nightly miri run

Run with Stacked Borrows model (strict aliasing)

使用Stacked Borrows模型(严格别名规则)

MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test
MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test

Disable isolation (allow file I/O, randomness)

禁用隔离(允许文件I/O、随机数生成)

MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test
undefined
MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test
undefined

5. What Miri detects

5. Miri可检测的问题

rust
// 1. Dangling pointer use
unsafe {
    let x = Box::new(42);
    let ptr = Box::into_raw(x);
    let _ = Box::from_raw(ptr);  // drop
    let _val = *ptr;  // Miri: use of dangling pointer
}

// 2. Invalid enum discriminant
let x: u8 = 3;
let e = unsafe { std::mem::transmute::<u8, MyEnum>(x) };
// Miri: enum value has invalid tag

// 3. Uninitialized memory read
let uninit: MaybeUninit<u32> = MaybeUninit::uninit();
let val = unsafe { uninit.assume_init() };  // Miri: reading uninitialized bytes

// 4. Stacked borrows violation
let mut x = 5u32;
let ptr = &mut x as *mut u32;
let _ref = &x;  // shared reference
unsafe { *ptr = 10; }  // Miri: mutable access while shared borrow exists

// 5. Data races (with threads)
// Miri simulates sequential execution and detects races via Stacked Borrows
rust
// 1. 悬空指针使用
unsafe {
    let x = Box::new(42);
    let ptr = Box::into_raw(x);
    let _ = Box::from_raw(ptr);  // 释放
    let _val = *ptr;  // Miri:检测到悬空指针使用
}

// 2. 无效枚举判别式
let x: u8 = 3;
let e = unsafe { std::mem::transmute::<u8, MyEnum>(x) };
// Miri:枚举值标签无效

// 3. 读取未初始化内存
let uninit: MaybeUninit<u32> = MaybeUninit::uninit();
let val = unsafe { uninit.assume_init() };  // Miri:读取未初始化字节

// 4. Stacked Borrows规则违反
let mut x = 5u32;
let ptr = &mut x as *mut u32;
let _ref = &x;  // 共享引用
unsafe { *ptr = 10; }  // Miri:存在共享借用时进行可变访问

// 5. 数据竞争(多线程场景)
// Miri通过Stacked Borrows模拟顺序执行并检测竞争

6. ThreadSanitizer for Rust

6. Rust中的ThreadSanitizer

bash
RUSTFLAGS="-Z sanitizer=thread" \
    RUST_TEST_THREADS=8 \
    cargo +nightly test -Zbuild-std \
    --target x86_64-unknown-linux-gnu 2>&1 | head -50
TSan output:
WARNING: ThreadSanitizer: data race (pid=12345)
  Write of size 4 at 0x7f... by thread T2 (mutexes: write M1):
    #0 myapp::counter::increment src/counter.rs:10
  Previous read of size 4 at 0x7f... by thread T1:
    #0 myapp::counter::get src/counter.rs:5
bash
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 (pid=12345)
  Write of size 4 at 0x7f... by thread T2 (mutexes: write M1):
    #0 myapp::counter::increment src/counter.rs:10
  Previous read of size 4 at 0x7f... by thread T1:
    #0 myapp::counter::get src/counter.rs:5

7. Miri configuration via MIRIFLAGS

7. 通过MIRIFLAGS配置Miri

FlagEffect
-Zmiri-disable-isolation
Allow I/O, clock, randomness
-Zmiri-strict-provenance
Strict pointer provenance (stricter than LLVM)
-Zmiri-symbolic-alignment-check
Stricter alignment checking
-Zmiri-check-number-validity
Check float/int validity
-Zmiri-num-cpus=N
Simulate N CPUs (for concurrency)
-Zmiri-seed=N
Seed for random scheduling
-Zmiri-ignore-leaks
Suppress memory leak errors
-Zmiri-tag-raw-pointers
Track raw pointer provenance
参数作用
-Zmiri-disable-isolation
允许I/O、时钟访问、随机数生成
-Zmiri-strict-provenance
严格的指针来源检查(比LLVM更严格)
-Zmiri-symbolic-alignment-check
更严格的对齐检查
-Zmiri-check-number-validity
检查浮点数/整数有效性
-Zmiri-num-cpus=N
模拟N个CPU(用于并发场景)
-Zmiri-seed=N
随机调度的种子
-Zmiri-ignore-leaks
抑制内存泄漏错误
-Zmiri-tag-raw-pointers
追踪原始指针的来源

8. CI integration

8. CI集成

yaml
undefined
yaml
undefined

GitHub Actions

GitHub Actions

  • name: Miri run: | rustup toolchain install nightly rustup +nightly component add miri cargo +nightly miri test env: MIRIFLAGS: "-Zmiri-disable-isolation"
  • name: ASan (nightly) run: | rustup component add rust-src --toolchain nightly RUSTFLAGS="-Z sanitizer=address"
    cargo +nightly test -Zbuild-std
    --target x86_64-unknown-linux-gnu
undefined
  • name: Miri run: | rustup toolchain install nightly rustup +nightly component add miri cargo +nightly miri test env: MIRIFLAGS: "-Zmiri-disable-isolation"
  • name: ASan (nightly) run: | rustup component add rust-src --toolchain nightly RUSTFLAGS="-Z sanitizer=address"
    cargo +nightly test -Zbuild-std
    --target x86_64-unknown-linux-gnu
undefined

Related skills

相关技能

  • Use
    skills/rust/rust-debugging
    for GDB/LLDB debugging of Rust panics
  • Use
    skills/runtimes/sanitizers
    for C/C++ sanitizer usage and comparison
  • Use
    skills/rust/rust-unsafe
    for unsafe Rust patterns and review checklist
  • Use
    skills/runtimes/fuzzing
    to generate inputs that trigger sanitizer errors
  • 若需使用GDB/LLDB调试Rust panic,请使用
    skills/rust/rust-debugging
  • 若需C/C++ Sanitizer的使用方法及对比,请使用
    skills/runtimes/sanitizers
  • 若需不安全Rust的模式及审查清单,请使用
    skills/rust/rust-unsafe
  • 若需生成触发Sanitizer错误的输入,请使用
    skills/runtimes/fuzzing