「C++ 代码卓越之道」第一章:数据流分析基础知识

原创
2023/12/22 10:24
阅读数 26

CLion 提供了一个内置数据流分析器,它会在您编写代码时持续运行并帮助提高代码质量。它可以显示各种代码问题,这些问题随后可能导致运行时问题、安全漏洞和其他漏洞。举例来说,这些有用的检查包括常量条件、死代码、null 指针取消引用、内存泄漏和数组索引问题。我们将发布一系列博文来说明 CLion 中某些检查的运作方式。

今天,我们将介绍数据流分析的基础知识,包括它的一般运作方式,同时介绍几个真实的例子,以帮助您编写出更好的代码。


控制流图

所有数据流检查都依赖于控制流图。它是一个图表,其中顶点是程序中的语句,边是这些语句之间的控制流跳转(直接代码执行、条件跳转、循环、中断、转到等)。

例如,右侧的控制流图表示左侧的 foo 函数:

基本示例

CLion 会为每个函数构建相应的图。每个图都有一个开始节点和一个退出节点,它们对应于函数的入口和出口。通过访问从开始节点到退出节点的图节点,CLion 可以收集一些有价值的信息。

例如,CLion 会记住每条语句的每个变量中可以存储哪些值。在上述示例中,CLion 知道在节点 0 和 1 处,形参 x 始终等于 1。这是因为函数 foo 只有一个调用点,它会传递实参中的值 1。因此,CLion 得出结论,节点 1 处的条件 x == 1 将始终为 true,因此控制流永远不会到达节点 3。在节点 4 处,变量 y 只能保存值 2,因为控制流只能来自节点 2,永远不会来自节点 3。因此,CLion 得出结论:

  1. 函数 foo 始终返回值 2

  2. 条件 x == 1 始终为 true

  3. 语句 y = 3 永远无法访问

现在,我们来看一个更复杂的示例:

带有控制图的更复杂示例

这里,我们有两个 if 块,第一个块的执行方式会影响第二个块的功能。为了支持这种评估,CLion 将 if 语句的 exit 语句拆分为两个不同的上下文:

拆分上下文

控制流图的后续节点重复。它们出现两次,第一次用于 if 语句的 Then 分支,第二次用于 Else 分支。在第一个“克隆”变量中,x 保存值 1(因为它对应于 if 语句的正分支),y 保存值 2(它存储在节点 2 中)。在第二个“克隆”变量中,x ! = 1y3

第二个条件 x == 1,对应于两个克隆的节点 45。在节点 4 处,条件始终保存 true,因为 x == 1。同时,在节点 5 处,它始终为 false。因此,节点 810 永远无法访问,条件 y == 2 只有一个可访问的克隆节点,即节点 9。在此节点处,y ! = 2,因此,此条件始终为 false。


数据流分析的实际运作情况

我们来看看这些技术如何帮助 CLion 在 C++ 程序中发现细微的 bug!我们决定分析 Z3 定理证明器,以下是我们在 CLion 中的数据流分析结果。

这里,变量 u 被初始化为 null_lpvar,然后可能被重新指定至相同的值(因为 if 条件中的 j == null_lpvar)。因此,条件 u == null_lpvar 始终为 true。由于这条 if 子句的 true 分支中有返回,所有后续代码都被标记为无法访问(报告为 #6951):

问题 6951

下面是另一个示例。这里,无符号变量 i 始终等于或大于零,并且在 else 分支中,它不为零。因此,i > 0 条件始终为 true(报告为 #6952):

问题 6952

在这篇博文中,我们介绍了我们的一项数据流检查 – 常量条件。CLion 还提供了许多其他数据流检查,我们将在接下来的博文中介绍其中一些。

立即试用

您认为代码分析在哪些情况下有用?请留言与我们分享您的例子!


本博文英文原作者:Anastasia Kazakova


CLion 相关阅读

关于 CLion

CLion 是用于 Windows、Linux 和 macOS 上 C 或 C++开发的智能 IDE。CLion 了解现代 C++ 标准并提供预处理程序支持。它还集成了 GDB/LDB 和一套单元测试框架。 

进一步了解 CLion

⏬ 戳「阅读原文」了解更多

本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部