
谷歌研究人员表明,他们能够将空间安全性“改造”到他们的 C++ 代码库中,而且对性能的影响非常小。
在分析了近 10 年的 CVE(从 2014 年 7 月 15 日到 2023 年 12 月 14 日)后,谷歌研究人员计算出 C++ 中至少 40% 的安全漏洞与空间内存漏洞有关(例如写入越界内存位置)。

在分析了近 10 年的 CVE(从 2014 年 7 月 15 日到 2023 年 12 月 14 日)后,谷歌研究人员计算出 C++ 中至少 40% 的安全漏洞与空间内存漏洞有关(例如写入越界内存位置)。
“我们现在已将其作为我们服务器端生产系统的默认设置,”博客文章解释道,同时密切关注其推出情况。
结果?
该团队发现了 1,000 多个漏洞。(Google 估计,平均每年可以发现 1,000 到 2,000 个漏洞。) Google 还经历了“整个生产过程中基线分段错误率降低 30%”。他们的博客文章将此归因于更好的代码可靠性和质量:“除了崩溃之外,检查还捕获了原本会表现为不可预测行为或数据损坏的错误。” 它最终还帮助 Google“识别并修复了十多年来潜伏在我们代码中的多个错误。”强化的 C++ 检查“将许多难以诊断的内存损坏转变为即时且易于调试的错误。” 它甚至扰乱了一次内部红队演习,“证明了其在阻止攻击方面的有效性”。

“我错了” 但有一个具体结果引起了最多的关注。谷歌的博客文章报告称,强化libc++“导致我们所有服务的性能平均下降了 0.30%”。 (他们甚至强调写道:“是的,只有三分之一个百分点……”)
他们的帖子得到了谷歌杰出工程师Chandler Carruth的回应,他也是新Carbon 编程语言的创始人和联合负责人。Carruth 写了一篇自己的博客文章,其中第一部分的标题是“边界检查的开销:我错了。”
“其他人对成本的大量历史报告以及我自己进行的一些相当随意的实验让我坚信边界检查不可能便宜到可以默认启用。然而,到目前为止,它们看起来非常实惠。”
不幸的是,这种普遍的观念使得高质量的动态安全检查无法进入libc++(和其他 C++ 库),并且最初也无法进入 LLVM。
强化 C 之路 但是 Carruth 看到基于编译器的检查已进入 Microsoft Visual C++,而“Apple 中推动C++ 中安全缓冲区的 LLVM RFC 的所有人在这里做出了出色的工作,让 LLVM 生态系统(包括 Clang 和 libc++)最终在这个领域拥有了可靠的工具。” Carruth 认为另一个因素是内存安全语言开发人员对 LLVM 的贡献更多(因为越来越多的非 C/C++ 语言开始使用它),带来了“一系列稳定而系统的改进”。
回顾过去,Carruth 认为 LLVM 经过了“许多年”的改进,“我认为我们并没有真正注意到临界点何时到来。在那个时候,它们结合起来从根本上降低了这些检查的实际成本,并使其默认且普遍地变得负担得起。
“这种级别的可用性改变了安全游戏规则,因为我们不再需要在性能或安全性之间做出痛苦的权衡,我们可以同时获得两者。”
Carruth 写道(用粗体字),通过努力,并且编译器继续支持内存安全检查,“我认为我们有机会默认实现空间内存安全,即使在 C 和 C++ 中,即使在性能最受限制的环境中也是如此。”
这就引发了一个问题:现在是否至少也应该考虑其他安全检查(例如引用计数)——即使我们认为这些检查也会对性能产生严重影响。
“我认为有一些令人信服的证据表明,对于较小的系统(手机、笔记本电脑、连接电池的设备),缓存流量和潜在同步开销的成本最多是微不足道的。我认为 Swift 已经提供了强有力的证据,证明只要在优化基础设施上进行一些投资并谨慎实施,引用计数在这些处理器上可以非常高效。”
当然,谷歌的帖子在 LinkedIn 上引发了更多讨论:
有无优化? Carruth 还回顾了“让 LLVM 在优化强化方面做得更好”的努力。他在这里建议,性能敏感的工作负载受益于配置文件引导优化 (PGO),以及“人们系统地构建优化基础设施……将代码的热路径与安全检查的开销隔离开来,并解锁 LLVM 围绕它们开发的所有其他优化技术,以最大限度地降低成本。”
说到谷歌,他们的博客文章确实承认了这一点和其他提高性能的技巧——然后补充说“即使没有这些先进的技术,边界检查的开销仍然很小。”(谷歌的博客文章反而将低影响归因于强化libc++设计高效的事实——以及编译器在优化过程中可以消除冗余检查的方式。)
然而,当他们发现 LLVM 执行了不必要的检查(这严重影响了性能)时,他们编写了一个修复程序并将其贡献给 LLVM 项目“以与更广泛的 C++ 社区分享好处”。
反应 Google 的帖子在网络上引起了一些积极的回应。在 Hacker News 上,它引起了 WebAssembly 联合创始人Ben Titzer的回应,他记得 20 年前曾争论过 C++ 中边界检查的必要性。“程序中存在边界检查可以捕获的错误。使其成为一种内置语言,可使其暴露于专门针对边界检查的编译器优化,从而消除许多错误并大大降低动态成本。
“仅在库中启用它们并不一定能暴露所有编译器优化,但这是一个开始。安全检查应该真正内置到语言中。”
另一个回复来自Walter Bright,他创建了替代的 Zortech C++ 编译器。Bright 也是系统编程语言 D 的创建者,他描述了20 年前 D 语言添加数组边界检查后发生的事情:“这是一个巨大的胜利。”在另一条评论中,Bright回忆起将边界检查设为 D 语言中的默认选项。“为了关闭数组边界,你必须打开一个开关,而且这只发生在标记为 @system 的代码中。
“事实证明,这是正确的举措。”
但也许最积极的回应来自Shane Miller (Rust 基金会的杰出顾问)在 LinkedIn 上发布的呼吁。“很高兴你们没有止步于通过这一举措来获取安全胜利。
“你们掌握的关于识别错误和提高可靠性的数据是极好的参考。”

评论