问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

对比C++,Rust在内存安全上做的努力

创作时间:
作者:
@小白创作中心

对比C++,Rust在内存安全上做的努力

引用
CSDN
1.
https://blog.csdn.net/qq_50764711/article/details/143872609

近年来,越来越多的组织建议在系统级开发语言选型时优先考虑Rust而非C/C++。谷歌数据显示,Android的安全漏洞从2019年的223个降低到2022年的85个,这一显著改善主要归功于Rust代码比例的增加。在Android 13中,已有约21%的新原生代码采用Rust开发。微软、AWS和Linux内核也相继引入Rust。那么,作为后来者的Rust是如何在内存安全方面取得如此显著成效的呢?

悬空指针

悬空指针是C/C++中常见的内存安全问题之一。当一个对象被释放后,如果还有指针指向该对象并尝试解引用,就会导致未定义行为。

在C++中,这种情况可能如下所示:

int main()
{
    std::string *ptr = nullptr;
    {
        std::string str;
        ptr = &str;
    }
    printf("%s", ptr->c_str());
    return 0;
}

而在Rust中,编译器会通过生命周期检查来避免这类问题:

fn main()
{
    let str_ref;
    {
        let str_obj: String = String::new();
        str_ref = &str_obj;
    }
    println!("{str_ref }");
}

尝试编译上述Rust代码时,编译器会报错,指出str_ref的生命周期超过了str_obj的生命周期:

缓冲区溢出

在C++中,使用原生数组进行索引操作时,如果没有边界检查,很容易导致缓冲区溢出。而在Rust中,即使是切片(对连续数据的引用),也会携带长度信息,从而在运行时检测到缓冲区溢出:

fn main() {
    let vec: Vec<i32> = vec![1,2,3];
    let vec_ref: &[i32] = &vec[0 ..];
    for i in 0 .. 4 {
        println!("{}", vec_ref[i]);
    }
}

运行上述代码时,Rust会抛出panic,明确指出缓冲区溢出:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 3', src/main.rs:7:17

对空指针进行解引用

在C/C++中,对空指针进行解引用会导致程序崩溃。而在Rust中,通过强制要求引用在使用前必须被赋值,以及使用Option类型来处理可能为空的情况,可以有效避免这类问题:

fn main() {
    let s: String = String::new();
    let s_ref: &String = &s;
}

对于可能为空的场景,Rust推荐使用Option类型:

fn main() {
    let mut s_ref_option: Option<&String> = None;
    
    let s: String = String::new();
    s_ref_option = Some(&s);
}

非法释放内存

在C/C++中,非法释放内存(如double free)会导致程序崩溃。而在Rust中,通过RAII(资源获取即初始化)机制,开发者几乎不需要手动管理内存:

pub trait Drop {
    // Required method
    fn drop(&mut self);
}

总结

Rust通过一系列创新机制,在内存安全方面取得了显著成效,得到了越来越多组织的认可。将其纳入技术栈,无疑是一个明智的选择。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号