P.MAC.PRO.01 不要使用过程宏来规避静态分析检查

【描述】

不要利用过程宏来定义能规避 Rust 静态分析检查的宏。

【反例】

在 Rust 生态中有一个库 plutonium,该库利用了过程宏来消除代码中直接的 unsafe 块的使用,从而规避了编译器对 unsafe 关键字的静态检查。

该库会通过#[safe] 过程宏在自动生成代码的时候为函数体添加 unsafe 块,但这会影响到 unsafe 调用链依赖静态检查传播,从而进一步打断 unsafe 调用链路,影响后续通过 unsafe 关键字来定位问题。

use plutonium::safe;

#[safe]
fn super_safe(x: f32) -> i32 {
    std::mem::transmute::<f32, i32>(x)
}

#[safe]
unsafe fn deref_null() {
    *std::ptr::null::<u8>();
}

fn main(){
    println!("{:?}", super_safe(1.0));
    deref_null();
}

【正例】

对于不安全的函数,应该显式地使用 unsafe 。这样做的好处是利用 Rust 编译器静态检查传播 unsafe 调用链条,以达到可以全局查找 unsafe 使用来消除一些代码隐患,方便定位问题。

unsafe fn super_safe(x: f32) -> i32 {
    unsafe { std::mem::transmute::<f32, i32>(x) }
}

unsafe fn deref_null() {
    unsafe { *std::ptr::null::<u8>(); }
}

fn main(){
    println!("{:?}", unsafe{super_safe(1.0f32)}); // 1065353216
    // error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
    // deref_null();  // 如果调用 unsafe 函数不加 unsafe 块,编译器就会报错。
    unsafe{ deref_null(); }
}

【相关讨论】