前文介绍CodeChecker时,使用到了Cppcheck,我们来看看这个工具是什么,如何使用。
1、Cppcheck介绍
Cppcheck 是 C/C++ 代码的静态分析工具。它提供独特的代码分析技术来检测缺陷,不检查代码中的语法错误,只检查编译器检查不出来的缺陷,并专注于检测未定义行为错误和危险的编码结构。其目标是减少误报、零误报,检查代码中真正的错误。Cppcheck旨在能够分析C / C++代码,即使它具有非标准语法(在嵌入式项目中很常见)。
Cppcheck既有开源版本,也有具有扩展的功能和支持的Cppcheck Premium版本,。可以访问 www.cppchecksolutions.com 以获取商业版本的更多信息和购买选项。
(1)Cppcheck功能特性
- 独特的代码分析,可检测代码中的各种错误。
- 命令行界面和图形用户界面都可用。
- Cppcheck非常注重检测未定义的行为。
(2)Cppcheck特有的分析技术
使用多个静态分析工具可能是一个好主意,每个工具都有独特的功能特性。这在研究中已经证实。那么Cppcheck的独特之处在哪里?
Cppcheck使用不健全的流程敏感分析,其他几种分析器使用基于抽象解释的路径敏感分析,这也很好,但既有优点也有缺点。从理论上讲,根据定义,路径敏感分析比流量敏感分析更好。但实际上,这意味着Cppcheck将检测其他工具无法检测到的错误。在Cppcheck中,数据流分析不仅是“前向”的,而且是“双向的”。大多数分析器会诊断这一点,可以确定数组索引为 1000 时会出现溢出。
Cppcheck还将诊断此问题,当x等于1000时,赋值时也会出现数组越界。
(3)未定义行为Undefined behaviour
- Dead pointers 死指针
- Division by zero 除以零
- Integer overflows整数溢出
- Invalid bit shift operands无效的位移操作数
- Invalid conversions无效转化
- Invalid usage of STLSTL 的用法无效
- Memory management内存管理
- Null pointer dereferences空指针解引用
- Out of bounds checking越界检查
- Uninitialized variables未初始化的变量
- Writing const data写入常量数据
2、Cppcheck安装
Cppcheck也可以从各种包管理器安装;但是,您可能会得到一个过时的版本。为了获取更新版本,可以访问https://github.com/danmar/cppcheck进行源码安装。
- Debian:
- Fedora:
- macOS:
3、使用入门
第一个测试程序,这里有一段简单的代码,我们命名为file1.c。
执行cppcheck file1.c,输出如下:
我们再试试上面说的例子,保存到file2.c。
执行cppcheck --enable=all file2.c,输出如下。可以看得出有2个warning和3个style问题。
(1)检查文件夹
Cppcheck支持检查文件夹中的所有文件。通常一个项目会有许多源文件,如果需要同时检查,Cppcheck 可以检查文件夹中的所有文件.如果 path 是一个文件夹,cppcheck 将递归检查这个文件夹中的所有源文件。
示例输出如下:
(2)手动检查文件或使用项目文件
使用 Cppcheck 可以手动检查文件,通过指定文件/文件夹来检查和设置,或者可以使用一个工程文件(cmake/visual studio)。
使用项目文件更快,因为它只需要非常少的配置。
手动检查文件可以更好的控制分析。
不一定哪种方法会有最好的结果,建议尝试一下,可能会得到不同的结果,发现大多数 bug 需要使用这两种方法。
4、严重级别Severities
输出信息中的严重级别支持如下几种:
- error 错误
when code is executed there is either undefined behavior or other error, such as
a memory leak or resource leak。发现未定义行为或其他错误,例如内存泄露、资源泄露 - warning告警
when code is executed there might be undefined behavior可能有未定义行为 - style样式风格
stylistic issues, such as unused functions, redundant code, constness, operator
precedence, possible mistakes.样式问题,例如未使用行数,冗余代码,常量性,操作符优先级,可能的错误等 - performance性能
run time performance suggestions based on common knowledge, though it is
not certain any measurable speed difference will be achieved by fixing these
messages.这些建议只是基于常识,即使修复这些消息,也不确定会得到任何可测量的性能提升。 - portability可移植性
portability warnings. Implementation defined behavior. 64-bit portability. Some
undefined behavior that probably works “as you want”, etc.可移植性警告。64 位的可移植性,代码可能在不同的编译器中运行结果不同。 - information信息
configuration problems, which does not relate to the syntactical correctness, but
the used Cppcheck configuration could be improved.配置问题,建议在配置期间仅启用这些
(1)启用消息
默认情况下,只显示错误消息,可以通过 --enable 命令启用更多检查。
- 启用警告消息:
- 启用性能消息:
- 启用信息消息:
由于历史原因 --enable=style 可以启用警告、性能、可移植性和样式信息。当使用旧 XML 格式时,这些都由 style 表示:
- 启用警告和性能消息:
- 启用 unusedFunction 检查。这不能通过 --enable=style 启用,因为不会在库中正常工作。
- 启用所有消息:
5、常见错误修改
- 隐式构造问题。
示例: (style) Class ‘Slice’ has a constructor with 1 argument that is not explicit。
解决方法:在Slice构造函数前加上explicit,使其必须显示构造,当然这种有时并非必须显示构造。
- 变量未初始化问题。
示例:(warning) Member variable ‘TableFileCreationInfo::file_size’ is not initialized in the constructor.
解决方法:在构造函数中加入变量初始值。
- 变量/函数未使用问题。
示例:(style) Unused variable: output。
示例:(style) The function ‘rocksmt_wal_iter_status’ is never used。
解决方法:考虑后期是否还需要,不需要的及时删除,需要的保留。
- raw loop问题。
示例:(style) Consider using std::fill algorithm instead of a raw loop. [useStlAlgorithm]。
示例:(style) Consider using std::transform algorithm instead of a raw loop. [useStlAlgorithm]。
解决办法:将循环便利替换为STL标准库算法函数。
- 引用传递问题。
示例:(performance) Function parameter ‘f’ should be passed by reference.
解决办法:在声明function时,能用引用传递的尽量使用引用传递,尽量避免值传递。
- const参数问题。
示例:(performance) Function parameter ‘s’ should be passed by const reference. [passedByValue]。
解决办法:形参s前加上const,在函数中未被修改的变量,尽量声明为const。