【问题标题】:How does Rust guarantee memory safety and prevent segfaults?Rust 如何保证内存安全并防止段错误?
【发布时间】:2016-07-08 06:23:53
【问题描述】:

我一直在寻找一种语言来学习,我发现 Rust 越来越受欢迎。

关于 Rust 的两件事让我印象深刻,内存安全和防止段错误。

Rust 如何做到这一点?例如,Rust 和 Java 之间的哪些区别启用了 Rust 的安全功能?

【问题讨论】:

  • Java 还保证内存安全并防止段错误(通过其 VM + 垃圾收集器),那么您在寻找 Java 和 Rust 之间的什么区别?另外,你读过the Rust Book吗? (它可能无法回答您的问题)。另外,你读过stackoverflow.com/questions/29628650/… 吗?
  • Java 使用跟踪垃圾收集器来保持所有对象处于活动状态,除了那些可证明无法访问的对象(因此它们的缺失是不可观察的)。 Rust 使用仿射类型系统,确保每个对象都有明确定义的生命周期和规则,禁止获取在引用对象生命周期之后仍然存在的引用。
  • 据我所知,Java不保证内存安全。
  • @Saibot:内存安全对你来说意味着什么 :)?

标签: memory-management segmentation-fault rust


【解决方案1】:

从本质上讲,Rust 如何实现内存安全实际上非常简单。它主要取决于两个原则:所有权和借款。

所有权

编译器使用仿射类型系统来跟踪每个值的所有权:一个值最多只能使用一次,之后编译器将拒绝再次使用它。

fn main() {
    let original = "Hello, World!".to_string();
    let other = original;
    println!("{}", original);
}

产生错误:

error[E0382]: use of moved value: `original`
 --> src/main.rs:4:20
  |
3 |     let other = original;
  |         ----- value moved here
4 |     println!("{}", original);
  |                    ^^^^^^^^ value used here after move
  |
  = note: move occurs because `original` has type `std::string::String`, which does not implement the `Copy` trait

这尤其避免了在 C 或 C++ 中经常遇到的可怕的double-free(在智能指针之前)。

借款

来自 Rust 的启示是,当混叠别名和可变性混合时会出现内存问题:也就是说,当一块内存可以通过多个路径访问并且它被变异(或移走)留下 悬空指针.

因此,借用检查的核心原则是:Mutability XOR Aliasing。原则上,它类似于读写锁。

这意味着 Rust 编译器跟踪 aliasing 信息,为此它使用 生命周期注释&'a var 中的 'a)连接引用的生命周期以及它们一起引用的值。

如果有人对某个值有引用或 INTO 引用,则该值被借用(例如,对 struct 的字段的引用或对集合的元素的引用)。借来的值不能移动。

可变性(无别名)

您在任何时候都只能获得单个可变引用 (&mut T) 到给定值,并且不能同时存在到该值的不可变引用时间;它保证您可以独占访问这些内存,因此您可以安全地对其进行变异。

别名(无可变性)

您可以随时将多个不可变引用 (&T) 获取到给定值中。但是,您不能通过这些引用 (*) 改变任何内容。

(*) 我在撒谎;有像RefCell 这样的结构实现“内部可变性”;他们确实尊重 Mutability XOR Aliasing 原则,但将检查推迟到运行时。

就这样?

差不多;)

对于编译器编写者来说实现起来已经相当复杂了,并且可能会过度限制用户(一些安全的程序使用这个系统无法证明是安全的,需要跳过箍),但是核心原则确实就这么简单。

那么还剩下什么?

边界检查。这不是火箭科学,但可能会导致性能损失。大多数语言对它都有一定程度的支持,C 是最大的例外,C++ 对它有一些支持,尽管它是可选的。

【讨论】:

  • 感谢您的回答。您想添加一些关于段错误预防的内容吗?
  • @Myra:分段错误只是内存访问不安全的症状之一。由于这里解释的机制,Rust 是内存安全的,因此没有分段错误,因为它没有内存损坏。
  • @Myra 使用 rust only segfault,您可以轻松引发“堆栈溢出”。任何其他段错误意味着编译器或使用不安全代码的库(以及通过 ffi 的 C 库)中存在错误。
  • @CatalinHritcu:宣传,真的吗? :D 重点主要放在时间安全上,因为它是 Rust 创新的地方。在空间安全方面,Rust 只是在运行时执行边界检查,就像几乎任何其他语言一样。已经有关于品牌索引的库实验,但没有直接的语言支持,“解决方案”很尴尬。
  • 动态边界检查在这里作为答案是有意义的,但这不是“几乎任何其他语言”所做的。像 C/C++ 这样的内存不安全语言不会对程序员进行这些检查。鉴于空间记忆安全与时间类型的安全性同样重要,我建议更新您的答案以反映这一现实,而不是让它听起来好像时间记忆安全是“它的全部”。我相信 Rust 足够了不起,它不需要宣传,默默地将“内存安全”等一般概念重新定义为“临时内存安全”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-09
  • 1970-01-01
  • 2017-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多