微软喜提Rust拟替代C/C++?凭什么!

2020-06-10 16:02:23 浏览数 (2)

今日 @开源中国 一则消息引发热议:微软计划将 Rust 作为 C 和 C 的安全替代品

根据微软安全响应中心提供的数据,所有微软年度补丁中约有 70% 是针对内存安全漏洞的修复程序。这样高的百分比是因为 Windows 和大多数其他微软产品主要使用 C 和 C 编写,这两种“内存不安全”(memory-unsafe)的编程语言允许开发人员对内存地址进行细粒度控制,并且可以执行代码。管理内存执行的开发人员代码中的一个漏洞可能导致一系列内存安全错误,攻击者可以利用这些错误带来危险和侵入性后果,例如远程代码执行或特权提升漏洞。 于是,探索使用诸如 Rust 之类的内存安全(memory-safe)语言被提上日程,这或将成为创建更安全的微软应用程序的替代方法。 xplanet,公众号:开源中国微软拥抱Rust,以作为C和C 的安全替代方案

其实,自操作系统诞生以来,系统级主流编程语言,从汇编语言到C ,已经发展了近50 个年头,但依然存在两个难题:

  • 很难编写内存安全的代码。
  • 很难编写线程安全的代码。

这两个难题存在的本质原因是C/C 属于类型不安全的语言,它们薄弱的内存管理机制导致了很多常见的漏洞。

可Rust 能解决这个问题多亏了Rust 语言所遵循的设计哲学之一:内存安全

现代编程语言早已发展到了“程序即类型证明”的阶段,类型系统基本已经成为了各大编程语言的标配,尤其是近几年新出现的编程语言。类型系统提供了以下好处:

  • 允许编译器侦测无意义甚至无效的代码,暴露程序中隐含的错误。
  • 可以为编译器提供有意义的类型信息,帮助优化代码。
  • 可以增强代码的可读性,更直白地阐述开发者的意图。
  • 提供了一定程度的高级抽象,提升开发效率。

一般来说,一门语言只要保证类型安全,就可以说它是一门安全的语言。简单来说,类型安全是指类型系统可以保证程序的行为是意义明确、不出错的。像C/C 语言的类型系统就不是类型安全的,因为它们并没有对无意义的行为进行约束。一个最简单的例子就是数组越界,在C/C 语言中并不对其做任何检查,导致发生了语言规范规定之外的行为,也就是未定义行为(Undefined Behavior)。而这些未定义行为恰恰是漏洞的温床。所以,像C/C 这种语言就是类型不安全的语言。

Rust 语言如果想保证内存安全,首先要做的就是保证类型安全。

在诸多编程语言中,OCaml 和Haskell 是公认的类型安全的典范,它们的类型系统不仅仅有强大的类型论理论“背书”,而且在实践生产环境中也久经考验。所以,Rust 语言借鉴了它们的类型系统来保证类型安全,尤其是Haskell,你能在Rust 语言中看到更多Haskell 类型系统的影子。

然而,直接使用Haskell 的类型系统也无法解决内存安全问题。类型系统的作用是定义编程语言中值和表达式的类型,将它们归类,赋予它们不同的行为,指导它们如何相互作用。

Haskell 是一门纯函数式编程语言,它的类型系统主要用于承载其“纯函数式”的思想,是范畴论的体现。而对于Rust 来说,它的类型系统要承载其“内存安全”的思想。所以,还需要有一个安全内存管理模型,并通过类型系统表达出来,才能保证内存安全。

简单来说,就是不会出现内存访问错误。只有当程序访问未定义内存的时候才会产生内存错误。一般来说,发生以下几种情况就会产生内存错误:

  • 引用空指针。
  • 使用未初始化内存。
  • 释放后使用,也就是使用悬垂指针。
  • 缓冲区溢出,比如数组越界。
  • 非法释放已经释放过的指针或未分配的指针,也就是重复释放。

这些情况之所以会产生内存错误,是因为它们都访问了未定义内存。为了保证内存安全,Rust 语言建立了严格的安全内存管理模型:

  • 所有权系统。每个被分配的内存都有一个独占其所有权的指针。只有当该指针被销毁时,其对应的内存才能随之被释放。
  • 借用和生命周期。每个变量都有其生命周期,一旦超出生命周期,变量就会被自动释放。如果是借用,则可以通过标记生命周期参数供编译器检查的方式,防止出现悬垂指针,也就是释放后使用的情况。

其中所有权系统还包括了从现代C 那里借鉴的RAII 机制,这是Rust 无GC 但是可以安全管理内存的基石。

建立了安全内存管理模型之后,再用类型系统表达出来即可。Rust 从Haskell 的类型系统那里借鉴了以下特性:

  • 没有空指针
  • 默认不可变
  • 表达式
  • 高阶函数
  • 代数数据类型
  • 模式匹配
  • 泛型
  • trait 和关联类型
  • 本地类型推导

为了实现内存安全,Rust 还具备以下独有的特性:

  • 仿射类型(Affine Type),该类型用来表达Rust 所有权中的Move 语义。
  • 借用、生命周期。

借助类型系统的强大,Rust 编译器可以在编译期对类型进行检查,看其是否满足安全内存模型,在编译期就能发现内存不安全问题,有效地阻止未定义行为的发生。

内存安全的Bug 和并发安全的Bug 产生的内在原因是相同的,都是因为内存的不正当访问而造成的。同样,利用装载了所有权的强大类型系统,Rust 还解决了并发安全的问题。Rust编译器会通过静态检查分析,在编译期就检查出多线程并发代码中所有的数据竞争问题。

微软拥抱Rust 并非偶然,其实早先微软已在Azure IoT 网络上部分使用了Rust。目前在商业领域,Rust 的重磅商业用户还包括:

  • Amazon,使用Rust 作为构建工具。
  • Atlassian,在后端使用Rust。
  • Dropbox,在前后端均使用了Rust。
  • Facebook,使用Rust 重写了源码管理工具。
  • Google,在Fuchsia 项目中部分使用了Rust。
  • npm,在其核心服务上使用了Rust。
  • RedHat,使用Rust 创建了新的存储系统。
  • Reddit,使用Rust 处理评论。
  • Twitter,在构建团队中使用Rust。

……

Rust 的前景越来越明朗,未来Rust 将大有可为。

本书并非对语法内容进行简单罗列讲解,而是从四个维度深入全面且通透地介绍了Rust 语言。从设计哲学出发,探索Rust 语言的内在一致性;从源码分析入手,探索Rust 地道的编程风格;从工程角度着手,探索Rust 对健壮性的支持;从底层原理开始,探索Rust 内存安全的本质。

本书涵盖了Rust 2018 的特性,适合有一定编程经验且想要学习Rust 的初学者,以及对Rust 有一定的了解,想要继续深入学习的进阶者。

专家力荐

  • Steve Klabnik,Rust 官方核心团队成员及文档团队负责人
  • Patrick Shaughnessy,《Ruby 原理剖析》原著作者
  • 唐刘,PingCAP 首席架构师,TiKV 负责人
  • 陈天,ArcBlock(区块基石)技术VP 终于看见由国内资
  • 杨梓杰(KiChjang@美国),Rust开发者,Servo资深贡献者
  • 孙晓光,知乎搜索技术架构Leader
  • 赵雪松(wayslog),BiliBili高级工程师
  • 唐刚,Rust Web框架Sapper作者
  • LeetCode(领扣网络)

0 人点赞