现代C ++不会拯救我们(2019年)

2021-04-26 12:18:28

我是一个常见的记忆不安全语言的批评者,主要是C Andc ++,以及他们如何诱导卓越的安全漏洞。基于来自来自众多大型软件ProjectSing C和C ++的证据的证据是,我们需要将业界迁移到内存安全的语言(如Rust和Swift)。我经常崇拜的一个回复是问题不是C和C ++本身,开发人员都是错误的。特别是,我经常接受表格的C ++的防御,“如果您不使用从C”1 overited的任何功能,则为C ++是安全的,如果您使用现代C ++类型和习语,则您将从内存损坏漏洞免疫困扰其他项目。

我想要信用C ++的智能指针类型,因为它们做得明显。不幸的是,我在大型C ++项目上工作的经验,其中过解释的成语是这些都没有足以阻止洪水的洪水。我的目标是这篇文章的剩余部分是突出完全现代C ++习语的数字,这产生漏洞。

我想描述的第一个例子,最初来自Kostya Serebryany,Ishow C ++的STD :: String_View可以轻松隐藏Freevulnersabilities:

#include< iostream> #include< string> #include< string_view> int main(){std :: string s =" helloooooooooooooo&#34 ;; std :: string_view sv = s +"世界\ n&#34 ;; std :: cout<< sv;}

这里发生了什么是S +"世界\ n"分配一个新的std :: string,然后转换为std :: string_view。此时,临时std :: string是释放的,但SV仍然指向它的内存,用于它的缺陷。未来使用SV是一种无用的脆弱性。哎呀!C ++缺少编译器的设施,以意识到SV捕获到参考生命长于参考的东西的引用。 thesame问题影响std :: span,也是一个非常现代的c ++类型。

#include<记忆> #include< iostream> #include<功能> std :: function< int(空白)> f(std :: shared_ptr< int> x){return [&](){return * x; };} int main(){std :: function< int(空白)> y(nullptr); {std :: shared_ptr< int> x(std :: make_shared< int>(4)); y = f(x); std :: cout<< y()<< std :: endl;}

这里,F中的[&]导致λ通过引用捕获值。然后主x超出范围,销毁对数据的最后一个引用,并导致它被释放。此时,Y包含一个悬空的指针。尽管我们整个智能指针使用了智能指针。是的,人们真的做了写作代码,处理std :: shared_ptr< t>&,&&&&&&&&&&&&&&&避免额外增加和减少参考计数。

std ::可选表示可能存在或不存在的值,通常授权魔术哨所值(例如-1或nullptr)。它提供了诸如值()的方法,其中提取它包含的t,如果可选是空的,则提取它包含的t并提出ANException。但是,它还定义了运营商*和运营商 - >这些方法还提供对Tundering Tuning T的访问,但是它们不会检查可选是否具有值或不值。

如果您使用std ::可选作为nullptr的替代,这可能会产生更严重的问题!取消引用nullptr为egfault(除了较旧的内核之外,egfault(除了安全问题之外)。取消引用无数无论何种,给您一个未初始化的值作为指针,这可能是一个严重的安全问题。在具有未初始化值的T *的同时是alsopossible,这些不太常见,而不是解除初始化为nullptr的指针。

否,这不要求您使用原始指针。您也可以使用智能指针举行/野生指针:

std :: span< t>提供符合人体工程学的方法来传递对阴道的阴记和长度的参考。这使您可以轻松地编写多种不同类型的代码;一个std :: span< uint8_t>可以点击由std :: vector< uint8_t&gt ;,一个std :: array< uint8_t,n>,oreal一个原始指针。无法正确检查边界是频繁的安全漏洞源,并且在许多感官中,SPAN有助于这种归因,您始终具有方便。

与所有STL数据结构一样,SPAN的运算符[]方法不执行界限检查。这是令人遗憾的,因为运营商[]是人们使用数据结构的Mostergonomic和默认方式。 STD :: Vector和STD :: Array至少可以理解地使用,因为它们提供了一个art()方法,它被检查(在练习中我从未见过此操作,但您可以想象一个采用静态分析工具的项目哪个简单的禁止调用std :: vector< t> ::运算符[])。 SPAN不提供AT()方法,或执行绑定查找的任何其他方法。

有趣的是,Firefox和Chromium的std :: span跨越Doperform界限检查运算符[],因此他们永远无法迁移到STD :: Span。

现代C ++习语介绍了许多有可能提升的更改:智能指针更好地表达了预期的生命,您始终具有正确的长度,STD :: Variant为工会提供了Asafer抽象。然而,现代C ++还介绍了某种可征的新漏洞:Lambda捕获使用的使用余额,无初始化的价值选项和未绑定的跨度跨度。

我的专业经验编写相对现代的C ++,以及审计生锈代码(包括使不安全的重大使用的铁锈代码)是,默认语言默认的语言和SWIFT(或Python和JavaScript)的Memory C ++ TheSuite of Method C ++根本没有匹配。发现生活中罕见的是一个有意义的程序,以便在Python或C ++中编写)。

将现有,大型,C和C ++ CodeBases迁移到不同的语言存在重大挑战 - 没有人可以拒绝这个。尽管如此,基本根本必须是我们如何完成它,而不是我们才能实现。即使有最现代化的C ++习语,证据明确表示,在规模上,它是根本无法持有C ++的权利。

我明白这是指原始指针,数组,手动Malloc /免费,以及其他类似的特征。然而,我认为值得承认的是,鉴于C ++将C显式纳入其规范,实际上大多数C ++代码都包含了一些这些元素。 ↩︎