1.5 编写会访问数据的测试预言机

在 harness 中验证引用有效性

译文 · 基于 Rust Fuzz Book

编写会访问数据的测试预言机

原文链接: https://rust-fuzz.github.io/book/cargo-fuzz/oracles-accessing-data.html

Rust 要求引用必须指向有效值,如 Rust 参考手册 所述:

引用或 Box<T> 必须对齐且非空,不能悬空,且必须指向有效值。

因此,高质量的 harness 应验证从目标库获得的每一个引用。

在 Rust 中用回调设计 API 非常灵活,但要为这类 API 编写良好的模糊测试 harness 并不容易。

1
2
3
4
5
6
pub fn api_with_callback(user_data: &[u8], callback: impl Fn(&[u32])) {
    let dangling_data_ptr: *mut u32 = process_user_data(user_data);
    let data_len: usize = HARDCODED_VALUE;
    let data = unsafe { std::slice::from_raw_parts(dangling_data_ptr, data_len) };
    callback(data);
}

在上例中,从悬空指针创建切片无疑是未定义行为(UB)。然而,当前模糊测试方案通常只配备地址消毒器(AddressSanitizer),只有在访问无效内存时才会检测到违规。因此,创建此类切片不会被地址消毒器捕获,效果取决于模糊测试 harness 的质量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 糟糕的 harness
fuzz_target!(|data: &[u8]| {
    api_with_callback(data, |lib_data| {});
});

// 良好的 harness
fuzz_target!(|data: &[u8]| {
    api_with_callback(data, |lib_data| {
        lib_data.iter().for_each(|byte_ref| {
            core::hint::black_box(*byte_ref);
        });
    });
});

在上述良好的 harness 中,lib_data 的每个字节都会被访问(并使用 black_box 避免访问被优化掉),任何无效内存访问都会被地址消毒器捕获,从而实现有效的缺陷检测。

如上所述,引用数据可以来自 API 的返回值,也可以来自回调参数。只要引用来自目标库,就应在模糊测试 harness 中检查该引用,以捕获 unsound 行为。除了手动编写检查模式外,touched 等 crate 也为此提供了便捷工具。

最后修改 August 23, 2026: 更新 (499855b16)