C++静态分析团队一直致力于提供各种工具来使开发者尽可能地编写安全的代码。感谢开发者的反馈和建议,我们添加了越来越多的代码安全检查规则并修复了一些对开发者影响比较大的Bug。在本文中,我将简要介绍最新的一项实验性功能:空指针引用错误。我还会将这项新功能和现有的类似检查做一个对比,看看新功能到底”新”在哪里。
概述从底层角度来看,我们实现了多个代码分析引擎。当然,这些底层引擎对于开发者来说是透明的,不管我们使用哪一套分析引擎,它们所激发的警告信息都是一致的。在这些代码分析工具中,有一些是用来检查空指针引用错误的,它们包括:C6011, C6387和C28196。这些警告信息对于开发安全的代码来说,确实非常有用,也帮助开发者规避了很多代码错误。
但是,它们针对现代C++新引入的一些特性还不能很好地支持。并且,它们所依赖的数据流框架也有着自身的限制。其中,EspXEngine就是我们创建用来解决这些问题的一个引擎。基于这个引擎,我们提供了很多路径敏感的数据流分析,例如Concurrency Check和Use After Move Check。这些检查十分奏效,这也促使我们将空指针检查也加入到这个引擎中。我们很高兴地看到新的版本相较于旧版本而言,添加了很多改进措施。
下面,我们来具体看看这些改进的细节信息,以及如何使用这些新的功能。
路径敏感的分析两种引擎都可以针对路径敏感的代码进行分析,我们考察下面的代码来进行理解:
在上面的代码中有很多分支语句。其中的一些分支互相之前存在一定的关联性,但是基于代码流的分析无法判断出这些关联性。例如,基于代码流的分析可能认为代码是不安全的,因为它判断出一个潜在的空指针,因为变量p在分支2中被设置成了nullptr,然后在分支3中又被使用了。但是,这个实际上不会发生,因为如果分支2被执行了,分支3就根本不会执行。而路径敏感的分析会判断这些代码可达性的条件并判断出上面的代码是安全的。但是要注意的是,这种精度的分析会花费更多的时间和内存。两种引擎针对这个代码片段,都会有着相同的行为模式。
本地分析两种分析引擎都会做过程式分析,所以它们不会看到跨越函数的边界,并且依赖类型,类型扩展,模型等。
上面的代码有一个Bug。因为对swap的调用,指针p会被设置为nullptr。在当前版本的代码检查中,这个Bug不能被检测到。而EspXEngine引擎就会发现这个错误并向开发者发出警告。但是有个问题,当我们调用我们自己的API时,EspXEngine不会知道被调用函数的具体语义。在这种情况下,我们可以使用类型或者SAL标记来描述函数中的前置和后置条件。
在上面的代码中,我们使用了_Notnull_和_Analysis_assume_这两个SAL标记来描述一些指针值上面所附加的限制。这种标记可以被两套引擎所支持。一个更加现代化的分案是使用更加丰富的类型来表达这些限制,而这个只能在EspXEngine中被支持。并且,当一个空指针被保存到一个gsl::not_null指针后,它会对代码做出标记,如下图所示:
而类型对于代码分析来说确实十分有用,SAL可以用来表达一个大范围的代码契约,我们看看下面的代码:
这个函数有一个复杂的后置条件。只要第一个参数为真,当函数存在时,位置 *p 处的值必须不为空。 两个引擎都理解这些契约(尽管 EspXEngine 中的支持更复杂),并且许多 Windows API 都被注释以描述它们的行为。我们很想使用标准的语言工具,但是 C++20 不接受契约式编程,我们需要一个既适用于C又适用于C++ API的解决方案。
现有空指针检查的问题下面我来展示一些代码例子,其中基于EspXEngine的空指针检查具有比当前更好的行为。 首先是一些当前检查规则中难以发现的空指针错误,如下图所示:
下面是一些不必要的警告:
在上面的代码中,当前版本将在注释行上给出空指针取消引用警告。 从技术上讲,当 malloc 失败并返回 nullptr 时,此警告可能是真实的。 这是一个与许多应用程序无关的场景。 EspXEngine 有低置信度警告和高置信度警告,在这种情况下只会发出低置信度警告。 大多数用户可能只对预计噪声较小的高置信度警告感兴趣并关闭低置信度警告。此外,我们决定让 EspXEngine 更严格地检测各种未定义的行为:
在上面的代码中,与 EspXEngine 相反,当我们在空指针上调用方法时,当前规则下不会触发警告。 严格来说,这段代码有未定义的行为,但是当方法没有取消引用 this 指针时,许多实现都可以正常工作。
在Visual Studio 2022 17.0 Preview 4中,我们将提供新的实验性质的代码检查,以查找空指针错误。 这些检查旨在成为当前检查的更好版本,具有更高的精度和附加功能。 这些新检查会进行深入的分析,所以会增加分析时间。在默认情况下,它们是关闭的,你可以使用CppCoreCheckExperimentalRules规则来启用它们。
总结我是觉得还不错。
最后Microsoft Visual C++团队的博客是我非常喜欢的博客之一,里面有很多关于Visual C++的知识和最新开发进展。大浪淘沙,如果你对Visual C++这门古老的技术还是那么感兴趣,则可以经常去他们那(或者我这)逛逛。本文来自:《Improved Null Pointer Dereference Detection in Visual Studio 2022 version 17.0 Preview 4》
最近我写了个东西正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。我想:你值得拥有。