逐渐而不起眼的情况是,当严重的C ++项目的复杂性变得令人望而却步时,就会出现这种情况。 不幸的是,现在C ++程序员不能仅仅依靠自己的优势。
首先,代码太多,以至于当项目中至少有几个了解整个项目的程序员时,就不再可能。 例如,Linux内核1.0.0包含大约17.6万行代码。 这很多,但是有可能在附近放置一台咖啡机,并在几周内或多或少地查看整个代码,并了解其操作的一般原理。 如果我们使用Linux 5.0.0内核,那么代码库的大小已经是大约2600万行代码。 内核代码增长了近150倍。 您只能选择项目的几个部分并参与其开发。 不可能坐下来弄清这一切是如何工作的,代码各部分之间的关系是什么。
其次,C ++语言继续快速发展。 一方面,这很不错,因为有些结构可以让您编写更紧凑,更安全的代码。 另一方面,由于向后兼容性,旧的大型项目变得异构。 他们交织了新旧代码编写方法。 用圆环比喻在树的一部分上。 因此,每年沉浸在用C ++编写的项目中变得越来越困难。 有必要同时理解代码,包括以C样式编写的类和现代方法(lambda,运动的语义等)。 完全学习C ++需要太多时间。 但是由于仍然需要开发项目,因此人们开始使用C ++编写代码,而没有研究其所有细微差别。 这会导致其他缺陷,但这是不合理的,因为这会停止并等待所有开发人员完全熟悉C ++。
情况无望了吗? 不行 可以使用一种新的工具:静态代码分析器。 此刻,许多经验丰富的程序员curl着嘴唇,好像滑了柠檬:)。 就像,我们知道这些是您的短毛猫...有很多信息,有点道理...是的,这种新型工具是什么? 我们在20年前推出了linter。
不过,我敢宣称这恰恰是一类新的工具。 10到20年前发生的事情根本不是现在称为静态分析器的工具。 首先,我不是在谈论面向代码格式的工具。 它们也与静态分析工具有关,但是现在我们正在谈论识别代码中的错误。 其次,现代工具使用复杂的分析技术,同时考虑到不同功能之间的相互联系,并且实际上是在虚拟地执行某些代码部分。 这些与基于正则表达式构建的20岁小动物不同。 顺便说一句,普通的静态分析器
根本不能对正则表达式执行操作。 为了发现错误,使用了诸如数据流分析,自动方法注释,符号执行等技术。
这些不是抽象的词,而是我作为PVS-Studio工具的创建者之一观察到的现实。 查看
本文 ,了解分析器为何会发现有趣的错误。
然而,更重要的是现代静态分析仪必须具有丰富的错误模式知识。 而且,分析人员甚至比专业开发人员还了解更多。 编写代码时要考虑并记住所有细微差别变得太困难了。 例如,除非您在某处专门阅读过,否则您永远都不会猜测对
memset函数以擦除私有数据的调用有时会消失,因为从编译器的角度来看,对
memset函数的调用是多余的。 同时,这是一个严重的安全漏洞
CWE-14 ,几乎可以在
任何地方找到它。 或者,例如谁知道这种容器填充有什么危险?
std::vector<std::unique_ptr<MyType>> v; v.emplace_back(new MyType(123));
我认为并非所有人都会立即意识到此类代码具有潜在的
危险,并可能导致内存泄漏。
除了对模式有广泛的了解外,静态分析器还可以专心致志且永不疲倦。 例如,与人不同,他们不太懒惰地查看头文件以确保
isspace和
sprintf是真实函数,而不是
疯狂的宏来破坏所有内容。 这样的情况说明了在大型项目中发现错误的难度的本质:某些地方在一个地方发生了变化,而另一处则破裂了。
我坚信,静态分析将很快成为DevOps不可或缺的一部分-它与使用版本控制系统一样自然和必要。 在专门针对开发过程的会议上,这种情况已经逐渐发生,在该会议上,越来越多地提到静态分析是解决bug的第一道防线。
静态分析是一种粗略的过滤器。 使用单元测试或手动测试来查找愚蠢的错误和错别字效率很低。 在编写代码后立即使用静态分析来发现问题,对其进行修复将更快,更便宜。 “
将静态分析嵌入到过程中,而不要寻找任何错误 ”一文中对此概念进行了很好的描述,以及定期使用分析仪的重要性。
也许有人会说专用工具毫无意义,因为编译器也学会了进行这种静态检查。 是的,是的。 但是,静态分析器自然不会停滞不前,而且专用工具的性能优于编译器。 例如,每次检查LLVM时,都会使用PVS-Studio在其中查找
错误 。
世界提供了大量用于静态代码分析的工具。 正如他们所说,
选择您的口味。 是否想在编写代码的阶段发现很多错误和潜在的漏洞? 使用静态代码分析器,提高代码库的质量!

如果您想与讲英语的读者分享本文,请使用此链接:Andrey Karpov。
为什么静态分析可以改善复杂的C ++代码库