在一个不安全的世界中的安全

主要观点:Joshua Liebow-Feeser 在 RustConf 上介绍其团队在 Fuchsia 操作系统工作时,在 Rust 类型系统中编码任意约束的方法。该方法虽不为 Rust 社区所陌生,但 Liebow-Feeser 很好地解释了该方法并强调应更广泛使用。
关键信息:

  • Netstack3 项目:Fuchsia 的新网络栈,完全用 Rust 编写,代码量大(63 个 crate 和 60 年开发工作量),过去一年已准备部署,在 60 台设备上运行良好,仅出现 3 个 bug,归功于在类型系统中编码重要不变量的方法。
  • 方法步骤:分为定义、强制和使用三步。定义时通过文档将 Rust 可推理的东西(通常是类型)与所需属性关联;强制时确保直接处理类型的代码维护相关不变量,使用字段隐私或 unsafe 标记防止不变量被破坏;使用时其他代码可依赖该属性。
  • 具体例子:包括二叉树确保节点间顺序不变量、Rust 标准库中通过 unsafe trait Send 保证非线程安全闭包不传递给 std::thread::spawn()、Netstack3 中的自动死锁预防(通过添加 mutex 名称、定义 unsafe 特质、创建新 Context 类型等方式)。
    重要细节:
  • Netstack3 前身 netstack2 在 Go 中实现时有很多死锁。
  • Send 是一个 unsafe trait,代表可在另一个线程安全运行的代码,编译器无法检查其属性。
  • 在死锁预防例子中,通过添加 generic Id 类型参数给 mutex 命名,定义 LockAfter 和 LockBefore 特质,添加 derive 宏和 blanket trait 实现来防止死锁。
  • 在运行时,与保证相关的类型级机制已被编译掉,无运行时开销。
    结论:实践中简化的死锁预防例子存在问题,但这种将语言未知属性“教”给 Rust 并在编译时强制的能力很重要,鼓励人们尝试该方法,认为这可重塑软件工程方式,是统一确保程序安全不同技术的良好框架。
阅读 4
0 条评论