引言 

静态代码分析是指无需运行被测代码,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,找出代码隐藏的错误和缺陷。

如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针引用等等。统计证明,在整个软件开发生命周期中,30% 至 70% 的代码逻辑设计和编码缺陷是可以通过静态代码分析来发现和修复的。

 

主流静态代码扫描工具概况 

腾讯TSC团队自主研发的tscancode工具、cppcheck、coverity、clang、pclint

 

费用和活跃度

竞品分析的选择了3款游戏项目(约500万行代码)。 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_空指针

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_内存泄漏_02

 

在可扩展性上,TSC有专人维护,定期根据用户需求扩展规则或新增功能特性,cppcheck和clang是开源工具,工具更新较慢,但如果用户有特殊需求可以自己扩展开发,pclint和coverity是商业软件,难以进行功能扩展。

同时,TSC有完整代码质量管理闭环平台QOC支持; coverity和clang可用web端的结果展示,但无法自行管理问题流,需要进行二次开发; cppcheck和pclint缺少web端结果展示。

准确性对比

 ​

4.1空指针规则 

空指针检查规则主要检查是否存在对赋值为空的指针解引用的情况,空指针是c/c++中最大的问题,经常造成程序崩溃的致命错误。因此,C++静态代码分析工具对空指针的检查能力显得尤为重要。

图为五个工具对样本代码扫描结果: 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_c++_03

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_代码分析_04

从报错数量和准确率来看:

有效报错数:TSC [401] >coverity[219]>>clang[57] >cppcheck[20]>pclint[14]

准确率: coverity[95%]≈TSC[92%] ≈clang[90%]>>cppcheck[28%]>pclint[14%]

综合评分: TSC[96分] >coverity[77分] >clang[56分]>cppcheck[18分]>pclint[8分]

 

4.2越界规则 

越界一般来讲是指数组下标越界,或者缓冲区读写越界。这类错误会导致非法内存的访问,引发程序崩溃或者错误。

下图是五个工具对样本代码扫描结果: 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_内存泄漏_05

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_web端_06

有效报错数:coverity[98]>>TSC [18]>pclint[16] >cppcheck[6]> clang[4]

准确率: clang[100%] >coverity[80%]>TSC[70%] >cppcheck[67%]>>pclint[2%]

综合评分:coverity[90分] >TSC[54分]≈clang[55分]>cppcheck[40分]>pclint[1分]

4.3变量未初始化规则 

变量未初始化顾名思义:变量声明后没有赋初值,其分配的内存值是随机的。这也是代码中容易出现的问题,会导致不确定的程序行为,造成严重的后果。

下图是五个工具对样本代码扫描结果: 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_web端_07

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_内存泄漏_08

有效报错数:coverity[75]>>pclint[25] >TSC [9]>cppcheck[8]> clang[1]

准确率: TSC[75%] >coverity[68%]>pclint[26%] > clang[17%] >cppcheck[3%]

综合评分:coverity[82分] > TSC[47分] >pclint[30分] > clang[10分] >cppcheck[6分]

 

4.4内存/资源泄露规则 

内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存,从而造成了内存浪费的情况。内存泄漏是静态下很难检测的一种错误,一般需要动态分析工具进行检测,如valgrind工具会捕获malloc()/free()/new/delete的调用,监控内存分配和释放,从动态上检测程序是否存在内存泄漏。因此,静态代码分析能检查的内存泄漏就非常有限了,当前各工具主要是从代码写法上检查内存分配和释放是否配对使用。比如:fopen打开文件后在退出函数前是否有执行fclose,new[]和delete[]是否配对使用等。

下图是五个工具对样本代码扫描结果: 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_web端_09

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_空指针_10

注:以上数据排除了cppcheck35个低价值报错,这里排除的cppcheck35个报错都是基本数据类型的new和delete不匹配(如char* p=new char[100];delete p;)虽然这种写法不规范,但由于实际上不会造成内存泄漏,很多项目不会对此进行修复。

从报错数量和准确率来看:

有效报错数:pclint[55] >TSC[40]>coverity [29]>cppcheck[28]> clang[0]

准确率: coverity[100%]=cppcheck[100%] >TSC[73%]>pclint[23%] > clang[N/A]

综合评分:coverity[79分] ≈ TSC [73分]≈cppcheck[77分]>pclint[57分]>clang[0分]

 

4.5逻辑错误规则 

逻辑错误:指可能存在的逻辑问题,如if不同分支内容相同,在switch内缺少break等,对指针使用sizeof进行空间分配等问题。

下图是五个工具对样本代码扫描结果: 

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_代码分析_11

【代码质量】静态代码检测pc-lint, visual lint, cpp-check(pclint、cppcheck)_空指针_12

注:这些报错中剔除了一些无修改意义且结果数量很多规则:如:coverity扫描存在7484条Logically dead code(逻辑代码不可达)报错。cppcheck存在2246条unusedFunction(函数未被使用)报错。

从报错数量和准确率来看

有效数量:TSC[293]>coverity[164]>clang[142] >cppcheck [120]>pclint[116]

准确率:clang[97%] >TSC[93%]>coverity(88%)>pclint[72%] >cppcheck[55%]

综合评分:coverity[94分] > TSC[86分] > clang[80分] >cppcheck[63分] >pclint[27分]