在Coverity的体系里,每一个被检测出来的缺陷,都会带上一个属于自己的CID编号,这个编号,就是用来标识和跟踪同一类问题的。想要弄明白在Coverity里面怎么去查看一条CID所对应的详细信息,关键就在于先在问题列表的视图里面,把那个CID给定位出来,然后再点进源码的详情页面,去细看它到底是被哪个检查器给揪出来的、触发的完整路径是怎样的、严重级别有多高,以及当前它处在什么样的处理状态之下。按照Coverity文档里的说法,你是可以直接拿这个CID编号去搜索特定问题的;同时也能通过不同角度的视图,比方说按项目、按组件、按问题本身的数据去分组,来把它给筛出来。
一、CID的详细信息要怎样去查看
去看一条CID的详情,可不是只扫一眼标题就完了的。真正要拿来判断这个缺陷到底需不需要去动手修改的,还得是缺陷的产生路径、它是在什么特定条件下被触发的,以及它此刻的分流状态,这几样东西,少了哪一个都可能判断走眼。
1、靠CID去搜索
先登进Coverity Connect的Issues页面,在搜索或者用来过滤的那个条件框里面,直接敲进你要找的那一串CID编号,就能把目标问题给锁定出来。要是项目里面的数据已经非常多了,那么在操作的时候,最好一开始就先把对应的那个Project、Stream或者Snapshot给选上,把范围收窄一下,然后再去搜CID,这样跳出来的结果才会更准,不至于在列表里翻半天。
2、把源码的详情给展开
等点击那个CID进到它的详情页以后,Coverity Connect里面那个专门展示源码的窗格,就会把这个缺陷到底发生在源文件的哪个位置上给标出来,并且还会附上一些嵌在行间的说明,帮助你理解这个问题是顺着怎样一条路径一步步走到这里的,以及该往哪个方向去修改它。
3、去查看检查器类型和事件的完整路径
到了这个页面,你要先去看一看这条缺陷是被哪一个Checker给报出来的,还有它归在什么缺陷类型里头。然后,再顺着它所列出的事件先后路径,从头往下摸一遍,看那个出问题的变量是从哪里被传进来的,在哪个判断分支里被做了什么样的处理,最后又是在哪一行代码上,终于触发了这次告警。像空指针、资源泄漏、越界访问这一类的缺陷,一定得把整条路径拉通看完,千万不能只瞥一眼最后那一行代码,前面的因果关系要是漏掉了,很可能就把真正的问题放了过去。
4、瞅一眼分流相关的几个字段
在一个CID的详细界面里,一般还会列出像分类、操作动作、严重级别,还有当前负责人这样一些跟分流有关的字段。在Coverity术语的解释里也特别提到过,Coverity Connect是会把分类、动作和严重级别这一整套分流数据,绑定到CID这个层面上来管理的,而不是仅仅关联到它在某一个版本里的一次偶然出现。
二、CID的历史变更记录该怎么去追溯
对一条CID做历史追溯,要盯着看的变化,主要就是三类:一是它底下的代码路径是不是已经变了;二是这个缺陷本身的状态是不是发生了改变;三是人工做过的那些分流记录有没有被调整过。千万不能只盯着它当前是什么样,要不然,将来就很难解释清楚,它到底是在哪个版本被引入进来的,又是在哪个版本被最终关掉的。
1、看一看跟快照有关的那些变化
进到CID的详情里面,去查一查它都出现在哪些快照版本里。如果某一枚CID,是从某一个特定的版本开始才突然冒出来的,那就说明在这个版本的附近,很可能引入了跟它相关的代码改动,或者构建的配置发生了变化;反过来说,要是在后续的某个快照里它忽然消失了,那么一般就可以判断它是被标记为已修复,又或者是那条曾经能触发它的代码路径,已经不复存在了。
2、翻一翻状态和人工分流的那些旧账
这一步,重点要去看的,是这枚CID是不是曾经从新建状态,一步步地变成了已分流、已忽略、有意的,或是已修复等等这些状态,以及到底是谁,在什么时候,去改动了它的分类、操作动作,或者把处理的责任人换成了别人。这串历史记录,对于我们判断这个问题到底被定性为误报,还是被决定暂缓处理,又或者已经真的把修改提交了上去,是最直接的凭证。
3、把代码提交的记录也给关联上
如果Coverity已经跟版本管理系统或者持续集成的流水线打通了,那在追溯的时候,就要去把CID出现的时间,跟代码仓库里的提交记录、分支合入的动作,还有构建号,统统对齐了来看。如果某一次CID的数量突然发生剧烈的变动,那背后的根源既有可能是代码真的被大改过,也有可能只是检查的规则集、构建的脚本,或者是分析的范围被人调整过了,这一点需要分辨清楚。
4、注意一条CID并不等于只出现那一次
要明白,同一个CID,是有可能横跨好几个快照版本,一直赖在那里不走的,而且也可能因为代码被挪动了位置、函数名被人改掉,或者那条用来合并的键值发生了变化,而表现出一些奇怪的状况。遇到那种好像重复出现的CID,或者感觉像是串了线的问题,就该去检查一下它的合并键、函数合并名这一类信息。在Coverity的社区里,大家排查重复CID的时候,通常也都会建议先去看一眼这些字段,确认一下是不是因为键值碰撞才闹出来的。
三、在对CID做复核的时候需要注意什么
当一条CID的追溯工作做完了,还不能算完,得把最后得出来的结论,清清楚楚地落到纸面上。要不然,等到下一次扫描,同一个问题又蹦出来了,团队里的人还得再花一份力气,去从头判断一遍,那是很浪费的。
1、对于被判定为误报的情况,一定要写下具体的理由
如果最后认定它是一个假阳性,那么在记录里可别只干巴巴地丢下“误报”两个字就走人。应该去说明,为什么你觉得那一条代码路径实际上是根本走不到的;为什么那个被报出来的指针,在运行到那里之前,其实已经被别处的逻辑保护起来了;又或者那块被说成是泄漏的内存,实际上是由框架层面去统一负责释放的。你写下的理由越具体,后面再有人来复审的时候,他们花在这上面的时间就会越少。
2、对于已经修好的情况,要看过复扫的结果才算数
开发人员把修修补补的代码提交上去之后,并不能光看提交说明里写的“已修复”就认定完事了,而是要等到下一次完整的扫描结果出来,亲眼确认那枚CID已经不再出现在列表里了。因为构建的配置、条件编译的生效范围,还有不同的代码分支,都有可能让同一个修改产生不一样的效果,只看提交说明是很不保险的。
3、对于被决定暂缓处理的问题,要写明在什么条件下才去处理
如果眼下放着没修,那就应该把这个问题的影响到底有多大、为什么现在暂时不能动它,以及计划在未来的哪一个版本里来处理它,这几条一并写明白。千万不要把那些仅仅是因为改起来比较棘手的问题,随手就标成没有风险,要不然,等到后续碰到安全审计或者质量审查的时候,当初这个动作会很难解释得过去。
总结
归纳起来,在Coverity里查看一条CID的具体详情,最常用的做法,就是先在Issues视图里面用编号把它给搜出来,再把源码的详情页展开,去仔细地看检查器的类型、事件发生的路径、严重等级,还有此刻的各种分流状态。而要追溯一条CID的变更历史,重点就得放在对比快照的变化、翻查状态和分流字段的修改记录,以及关联那段时间的代码提交上面。
