C++发布革命性提案:“借鉴”Rust精华,内存安全即将成为标配?

科技   2024-09-19 07:58   浙江  
转自:InfoQ - 核子可乐、Tina
想要内存安全?那就给你们内存安全!我们也有自己的借用检查器。

在被“内存安全”议题反复折磨了两年之后,C++ 社区已经发布一项提案,旨在帮助开发人员减少代码中的安全漏洞。

这项 Safe C++ Extension 安全扩展提案希望解决这种编程语言中的致命弱点,保证其就此告别内存安全漏洞。

C++ 联盟总裁兼执行董事 Vinnie Falco 上周四表示,“这是一项革命性的提案,将为 C++ 编程语言带来内存安全功能。这次合作也标志着 C++ 生态系统的一个重要里程碑,相信大家也感受到行业对于安全代码的需求从未如此迫切。”

1 内存安全的需求确实从未如此迫切

在过去两年之间,各类私营和公共部门组织一直在敦促和推动程序员们使用内存安全语言(例如 C#、Go、Java、Python 以及 Swift)编写新应用程序,同时重写旧有应用程序。其中最典型的选项当数 Rust,一款性能良好的低级系统语言。

软件工程师 Alex Gaynor 早在 2019 年就提出了这个问题,他表示大型代码库中的大多数严重漏洞都来自内存安全缺陷,例如缓冲区溢出与释放后使用。他强调称,“数据已经一再证明,当项目使用内存不安全语言(例如 C 和 C++)时,就会受到大量由此产生的安全漏洞的困扰。”

在此之后,内存安全迅速成为学术论文和技术会议中常见的讨论主题。2022 年 9 月,微软 Azure 首席技术官 Mark Russinovich 也下场静态,呼吁开发人员弃用 C 和 C++,转投 Rust 的怀抱。

几个月后,美国国安局也采取了类似的立场。到 2023 年,内存安全已然成为主流话题,Consumer Reports 消费者报告也对此进行了报道。

面对 Rust 的浩大攻势,C++ 阵营这边则警惕地组织起防守阵形。两年之前,在回应 Russinovich 对于弃用 C/C++ 的呼吁时,C++ 语言的缔造者 Bjarne Stroustrup 就在采访中坦言,“们现在可以在 ISO C++ 中实现完美的类型与内存安全保障。

然而这个说法遭到了一些质疑。互联网安全研究小组(ISRG)的联合创始人兼执行董事 Josh Aas 就负责监督一项名为 Prossimo 的内存安全计划,他去年曾在采访中证实,尽管理论上确实可以编写内存安全的 C++ 代码,但其在现实中其实无法实现,因为 C++ 并没有在立项之初就考虑到内存安全设计。

安全 C++ 扩展提案就是为了解决这些批评而生,同时也响应了美国国安局、其他五眼国家情报机构、美国网络安全与基础设施安全局(CISA)白宫以及国防高级研究计划局(DARPA)对于各公共部门提出的内存安全要求。

今年 8 月,Gaynor 重新讨论了内存安全问题,并指出虽然尝试让 C++ 更安全确有现实意义,但他仍对这种意义的具体程度表示怀疑。“我的态度很明确,C++ 的安全性可以得到实质性改进。更具体地讲,完全解决内存安全问题似乎也不是不可能。但相信大家也跟我一样有着同样的共识,那就是对于让 C++ 在安全性方面比肩 Swift、Go 或者 Rust 这个问题上,恐怕并不存在一个简单易行的解决方案。”

尽管如此,安全 C++ 扩展提案仍想要一试身手。C++ 联盟开发人员 Sean Gaxter(Circle 编译器的创造者)与 Christian Mazakas 承认,目前行业对于采用内存安全编程语言的呼声可谓震耳欲聋。在他们看来,虽然 Rust 只是一种流行的系统级编程语言、没有垃圾收集功能、可以提供严格的内存安全保障,但将 C++ 代码迁移至 Rust 还是会带来很多问题。

2 将大量 Rust 内容复制到了 C++ 中?

https://safecpp.org/draft.html

他们在提案中解释道,“Rust 缺少函数重载、模板、继承和异常机制,C++ 则缺少特征、重新定位与借用检查。这些差异也导致这两种语言在对接时产生种种不匹配状况。大多数用于跨语言绑定的代码生成器,根本就无法用某一种语言的特性来表达另一种语言的特性。”

尽管 DARPA 正在尝试开发出更好的 C++ 到 Rust 自动化转换工具,但 Baxter 和 Mazakas 认为,强迫资深 C++ 程序员们学习 Rust 并不是理想的答案——不久之前,一位专注于 C 语言的 Linux 内核维护者甚至因此辞去了工作。

他们争辩道,“Rust 对于职业 C++ 开发者来说差异性过大,再加上互操作工具不够便利,就导致通过用 Rust 重写关键部分以强化 C++ 应用程序变得极其困难。所以,为什么没有针对内存安全的语言解决方案?为什么就没有安全版的 C++?”

Baxter 还在采访中提到,尽管过去几十年来,无数计算机科学家一直在关注如何对程序的正确性做出证明,但现如今这个问题已经上升到了核心国家安全的高度。

Baxter 解释称,“近期政府对于内存安全问题的警告,促使整个科技行业都在关注这个问题。我研究了这一理论,并从中发现了新机会:设计新工具,帮助 C++ 工程师们编写出质量更高的程序,同时消除与安全漏洞相关的各类软件缺陷。

Baxter 还指出,安全 C++ 项目引入了保障内存安全的新技术,而不仅仅是对原有最佳实践的重申。“安全 C++ 能够防止用户编写出不健全的代码,同时辅以编译时智能,例如通过借用检查来防止使用后释放错误、初始化分析以确保类型安全等。”

Baxter 表示,用不同编程语言重写项目的成本很高,所以安全 C++ 的目标是以更低的成本实现与 Rust 相同的健全性保证,进而降低内存安全的准入门槛。他解释道,“有了安全 C++,现有代码能够像以往一样继续正常运行,而各利益相关方则可以更好地把控程序安全。”

至于下一步,还需要科技行业的更多参与,以帮助实现安全 C++ 提出的项目目标。

他总结道,“基础已经打好:我们有了出色的借用检查和初始化分析机制,这也是健全性保障的实现基础。下一步是全面对接 C++ 的所有功能特性,并为其指定内存安全版本。这是一项艰巨的工作,但考虑到减少 C++ 安全漏洞的重大意义,这份付出绝对物有所值。”

社区对此提案褒贬不一。

有人提到,“这个话题如此重要,令人难以置信的是它还没有进入主流新闻”。他还表示,经过几十年不安全和脆弱代码的困扰,终于有了一个官方且实用的“智能感知”机制来确保代码的正确性,不过迟到总比不到好。

另一位二十多年的资深 C++ 开发 James20k 认为,“在 C++ 内存安全的所有提案中,这个提案感觉是迄今为止最明智的。”

他认为该提案最大的优点是基于实际的,且它是完全可选的,对现有的 C++ 不会发生任何变化。而且已被证明是可实现的,不像其他替代方案。Carbon、cpp2、clang-lifetimes、profiles 等要么内存不安全,要么无法完全实现,要么就是没有用。另外,它提供了一个完全内存安全的 C++ 版本,并且没有损失表达能力。

但他指出这个提案的一个缺点就是“明确地基于 Rust”,“你已经能看到这引发的强烈争论了。遗憾的是,委员会对此类事情也并非免疫。”

很明显,社区中一部分技术人员对借鉴 Rust 中的内容有些异议。

我希望他们不要加入借用检查器,也不要把 C++ 变成某种奇怪的 Rust 混合体。我真的比 Rust 更喜欢 C++。我喜欢 C++ 带来的自由,我认为这也是它的主要卖点之一。

我原本以为会看到一个关于 C++ 安全性的方案,但这个规范中大量借鉴了 Rust 的内容,应用在 C++ 上。正因为有这样的预期差异,阅读过程中有时觉得像是在看一场恶搞。就像,作者是不是在开玩笑,把 Rust 的内容用 C++ 语法呈现,称之为“安全 C++”?

不过,看起来这确实是一个经过深思熟虑的提案,作者投入了大量精力。对作者们来说,干得不错!现在谈谈我的实际想法:我个人认为,这个提案对语言的改变太大了,甚至比 C++11 的变动还要大。我真的很想问,这是唯一的方式吗?或许这是目前唯一经过验证的方式。也许随着更多人关注这个提案,有人可以在此基础上进一步改进规范,如果这样的改进是可能的话。

我并不反对在 C++ 中加入安全性改进的想法。但这个提案给我的感觉像是“试图让 C++ 变得像 Rust”。Rust 确实有一些很好的特性,但我们的目标应该是以 C++ 自己的方式进行改进,而不是试图成为另一种语言。
3 Linus Torvalds 出言定性:Rust 带来了新的“信仰之争”

有开发者认为,C++ 要么朝这个方向发展,要么输给 Rust 并消亡。

这种观点反映了编程语言之间的竞争往往被过度情绪化,也是一种引战的言论。C++ 和 Rust 都是工具,没有谁需要“胜利”,但每次在 C++ 社区中提到 Rust,都会引发一场老式的口水战。这种 C++ 和 Rust 之间的“文化战”往往让人想起 C 和 Rust 之间的争论。

在 Linux 缔造者 Linus Torvalds 看来,如今Rust 带来的争议,“几乎上升到了带有宗教战争色彩的信仰之争层面”。

在 9 月 16 日最新开源峰会的主题演讲当中,Torvalds 评论了 Linux 社区中 C 与 Rust 之争。最近,微软软件工程师、Rust for Linux 维护者之一 Wedson Almeida 在给 Linux 内核邮件列表 (LKML) 的一封信中表示自己已经退出了该项目。在 Linux 内核圈子里,一些开发人员和维护人员不想与 Rust 有任何关系,他们毫不避讳地表达了他们认为该编程语言已经失败的观点。

对此,即使是不介意争论的 Torvalds 也承认,“有些争论很激烈。”

Torvalds 强调,“我其实并不反感争论,毕竟真理越辩越明。我认为 Rust 的一大优点,在于它能让某些讨论焕发生机,但也会让不少争论变得非常激烈……这至少表明很多人正深切关心这门语言。可另一方面,我也不太理解为什么 Rust 总会成为激起争议的核心。这让我想起年轻那会,人们关于 vi 和 emacs 的大战。不过出于某种原因,感觉 Rust 和 C 的讨论几乎上升到了带有宗教战争色彩的信仰之争层面。”

这场争议可以追溯到三年之前,当时就有人提出“Rust 可以成为内核项目的一部分甚至取代 C 语言”的观点。此时一切还都很正常,可后续情况却很快走向了失控的边缘。例如,使用 C 语言可能在 CPU 上产生著名的缓冲区溢出漏洞,但目前这类情况已经很少出现。虽然 Rust 能够提供某些安全功能,但也有自己的弊端,毕竟与相对容易掌握的 C 语言相比,其学习曲线明显更加陡峭。

正如 Torvalds 在演讲中的解释,C 是一种相对“容易掌握的语言”,这也是“我喜欢 C 的原因之一,更是很多 C 语言程序员喜欢它的原因之一——但同时也必须承认,正是因为它很简单,所以很容易在使用时犯错误。而 Rust 则完全不同。有很多人已经习惯了 C 的思考模式,所以不一定能接受这种差异,但这其实没什么。”

不过必须承认,C 和 Rust 两派的分歧很大。Torvalds 进一步指出,“有些人就是不喜欢 Rust 提出的概念,也不喜欢 Rust 侵占自己的领域……不少人甚至断言 Rust 的融合之路是失败的。我之前就对此表达过反对——我们已经在这方面探索了几年,所以目前下结论还为时过早。但我也认为,哪怕是失败了(虽然我并不支持这种失败论),这也是学习经历的一部分。所以我觉得推广 Rust 是有积极意义的,可争论过程中的很多人似乎并不这么看。”

Torvalds 表示,挑战在于内存安全架构对于基础设施做出了某些假设。

“基础设施人员可能会对此感到害怕,但这已经是个公开的秘密了。换言之,基础设施人员似乎在抵制这些变化。公平地讲,我们对 C 基础设施也做了不少改变。内核编码其实在很大程度上也超出了常规的 C 语言范畴,我们不仅会以某种方式编写代码,同时也在 C 语言这边部署了很多用于执行语言之外基础设施规则的工具方案。这就是我们对于安全性的探索和保障。我们在 C 语言这边其实建设了大量内存安全基础设施,从技术上讲它们并不属于 C 的组成部分——而更多是我们内核基础设施的组成部分。我们拥有调试版本,能够让内核运行得更慢,同时对更多内存安全要素进行测试。”

很明显,Rust 和 C 语言各擅胜场。Rust 支持者们拿出了大量有力的论据(只要能够编译通过,代码质量就有保障;而且泛用性更好等),而 C 语言派则认为这位老将更容易学习,而且在过去数十年的开发应用中积累下了巨大的生态财富,更适用于以内核为中心的 eBPF 开发。

正如思科 Isovalent 首席开源官 Liz Rice 在采访中所言,Rust 更新,具有“非常强大的优势,但并不是每个人都能立即适应并掌握 Rust 的开发思路。不少在内核中开发 eBPF 子系统的人们,绝不可能突然转过身来选择 Rust 来完成日常工作。其实很多人都在讨论这个问题,比如说「如果我们能用 Rust 处理所有开发任务,那 eBPF 验证器就可以直接删掉了,根本不需要它。」但我认为持这种说法的朋友,其实没有完全理解 eBPF 验证器的全部作用。我们可以用 Rust 编写 eBPF 代码并将其编译为 eBPF 字节码,这才是想要编写 eBPF 的 Rust 开发者所应当选择的路线。”

与此同时,Polar Signals 公司 CEO 兼创始人 Frederic Branczyk 也在采访中强调,“Rust 中亦有不少实例证明,开发者必须先做一些非安全实践,之后在此基础上建立起安全的抽象。所以我绝不认为 Rust 会成为搞定一切的万灵药。顺带一提,我本身是 Rust 的忠实粉丝,可虽然 Rust 也能完成很多工作,但我还是认为 C 才是操作系统编写方面的理想语言。”

延伸阅读:

C++ 之父 Bjarne Stroustrup:我会为全球数十亿行 C++ 代码带来一个崭新的解决方案

参考链接:

https://cppalliance.org/vinnie/2024/09/12/Safe-Cpp-Partnership.html

https://safecpp.org/P3390R0.html

https://www.youtube.com/watch?v=OM_8UOPFpqE&t=510s

https://www.theregister.com/2024/09/16/safe_c_plusplus/?td=rt-3a

https://www.youtube.com/watch?v=OM_8UOPFpqE&t=510s

https://thenewstack.io/linus-torvalds-c-vs-rust-debate-has-religious-undertones/

https://www.zdnet.com/article/linus-torvalds-muses-about-maintainer-gray-hairs-and-the-next-king-of-linux/

https://www.reddit.com/r/cpp/comments/1fiuhb7/the_empire_of_c_strikes_back_with_safe_c_proposal/


推荐阅读  点击标题可跳转

1、手撸一个内存分配器

2、巧活用折叠表达式

3、嵌入式 C 语言,那些“花里胡哨”的语法特性。

CPP开发者
我们在 Github 维护着 9000+ star 的C语言/C++开发资源。日常分享 C语言 和 C++ 开发相关技术文章,每篇文章都经过精心筛选,一篇文章讲透一个知识点,让读者读有所获~
 最新文章