Cppcheck是一个用于C/C++代码的静态分析工具,它可以帮助开发者检测代码中的错误。Cppcheck可以检测出许多类型的错误,包括语法错误、未使用的函数、内存泄漏、未初始化的变量等。此外,Cppcheck还支持用户自定义规则,这使得开发者可以根据自己的需求定制Cppcheck的行为。
主要选项
- 错误(error):这是最严重的问题,Cppcheck 100%确定这是错误。例如,数组越界,空指针解引用等。
- 警告(warning):Cppcheck认为代码看起来有问题,但它并不确定这是否真的是错误。例如,有可能发生整数溢出,有可能发生除以零的情况等。
- 样式(style):这些是关于代码风格的问题,例如未使用的函数、多余的代码等。
- 可移植性(portability):当代码在不同的平台上运行时可能会出现问题。例如,使用了不可移植的函数,或者依赖于编译器特定的行为。
- 性能(performance):Cppcheck会发出警告,如果代码可以优化以提高性能。
- 信息(information):这些是一些有趣的,非关键的信息,通常可以忽略。
这些选项可以通过命令行参数进行启用或禁用,以定制Cppcheck的行为。例如,如果你只关心错误和警告,你可以使用--enable=warning,error
参数来运行Cppcheck。
检查范围
以下是 Cppcheck 的主要检查范围:
- 未定义行为:包括死指针、零除、整数溢出、无效的位移操作数、无效的转换、STL的无效使用、内存管理、空指针解引用、越界检查、未初始化的变量、写入const数据等。
- 安全性:Cppcheck 可以检测到一些常见的安全漏洞,如缓冲区错误、不当的访问控制、信息泄露等。
- 编码标准:Cppcheck 支持多种编码标准,包括 Misra C 2012、Misra C++ 2008、Cert C、Cert C++ 等。
- 其他检查:Cppcheck 还有许多其他的检查,具体可以参考 这个链接。
cppcheck / Wiki / ListOfChecks
检查器
开启/关闭检查器
Cppcheck允许你通过命令行参数来启用或禁用特定的检查器。你可以使用--enable=
参数来启用特定的检查器,或者使用--disable=
参数来禁用特定的检查器。
例如,如果你只想启用内存相关的检查,你可以使用以下命令:
cppcheck --enable=warning,performance,portability,information,missingInclude --suppress=missingIncludeSystem yourfile.cpp
这个命令将启用所有的警告,性能,可移植性,信息和缺失包含的检查,但是会抑制系统缺失包含的警告。
你可以在Cppcheck的官方手册中找到更多关于如何使用这些参数的信息。手册中详细介绍了每个参数的用途和如何使用它们。
请注意,你需要根据你的需求来选择启用或禁用哪些检查器。不是所有的检查器都适合所有的情况,所以你需要根据你的代码和你想要检查的问题来选择合适的检查器。
默认检查器
Cppcheck的默认检查器包括:
- 错误(error):这类检查器主要检测可能导致程序崩溃或者运行不正常的问题,例如内存泄漏、数组越界、未初始化的变量等。
- 警告(warning):这类检查器主要检测可能导致程序表现不如预期的问题,但不一定会导致程序崩溃,例如未使用的函数、未使用的变量等。
这两类检查器是默认启用的,无法被关闭。
对于其他的检查器,如样式(style)、性能(performance)、可移植性(portability)等,你可以通过--enable
参数来启用或禁用。例如,如果你想启用所有的检查器,你可以使用--enable=all
参数。
获取检查器列表
你可以通过命令行应用程序获取所有已实现的检查器的当前列表:
- 取检查器列表
cppcheck --doc
- 获取错误消息列表
cppcheck --errorlist
内存泄漏相关检查
在Cppcheck中,内存泄漏检查是默认启用的。这意味着,即使你没有指定任何参数,Cppcheck也会检查内存泄漏。这是因为内存泄漏是一种严重的问题,所以Cppcheck默认总是检查它。
Cppcheck是一个静态分析工具,它可以检查C/C++代码中的多种类型的内存泄漏,包括但不限于:
- 未释放的内存:当程序使用
malloc
、calloc
、realloc
或new
分配内存,但没有使用free
或delete
释放它时,会发生内存泄漏。 - 未关闭的文件:当程序使用
fopen
或其他函数打开文件,但没有使用fclose
关闭它时,会发生资源泄漏,这也可以看作是一种特殊的内存泄漏。 - 未释放的系统资源:当程序使用系统API分配资源(例如,使用
socket
函数创建套接字),但没有使用相应的函数释放它时,会发生资源泄漏。
然而,Cppcheck作为一个静态分析工具,它的检查是基于源代码的,而不是基于程序的运行状态。这意味着它有一些局限性:
- 动态行为:Cppcheck可能无法准确地检测出由于程序的动态行为(例如,条件分支、循环、递归、并发等)导致的内存泄漏。
- 复杂的数据结构:如果程序使用了复杂的数据结构(例如,链表、树、图等),并且内存管理逻辑也很复杂,Cppcheck可能无法准确地检测出内存泄漏。
- 间接的内存泄漏:如果内存泄漏是通过间接的方式发生的(例如,通过函数指针、虚函数、回调函数等),Cppcheck可能无法检测出它。
- 外部库和系统API:如果内存泄漏是由于错误使用外部库或系统API导致的,Cppcheck可能无法检测出它,除非这些库和API已经被Cppcheck的开发者显式地支持。
因此,虽然Cppcheck是一个非常有用的工具,但它不能替代其他类型的内存泄漏检查工具和技术,例如动态分析工具(如Valgrind)、代码审查、测试等。
性能相关
Cppcheck可以检查一些性能相关的问题。你可以通过以下命令来启用性能相关的检查:
cppcheck --enable=performance yourfile.cpp
这个命令将启用性能相关的检查,不会启用其他的检查器。
性能检查可以帮助你找到可能影响代码运行效率的问题,例如未使用的变量,未使用的函数返回值,以及可能导致性能下降的编程模式等。
Cppcheck是一个静态分析工具,它可以检查C/C++代码中的各种问题,包括性能问题。以下是Cppcheck可以检查的一些性能问题类别:
- 未使用的函数:如果代码中有未使用的函数,这可能会浪费内存和CPU资源。
- 未使用的变量:同样,未使用的变量也可能会浪费内存。
- 过度复杂的函数:如果一个函数过于复杂,它可能会导致CPU使用率过高。
- 过大的栈使用:如果一个函数使用了过多的栈内存,这可能会导致栈溢出,从而导致程序崩溃。
- 过度的循环:如果一个循环运行的次数过多,或者循环中的代码过于复杂,这可能会导致性能问题。
然而,Cppcheck的性能检查也有其局限性。以下是一些主要的局限性:
- 静态分析的局限性:Cppcheck是一个静态分析工具,它只能检查代码的静态特性,不能检查运行时的性能问题。例如,它不能检查内存泄漏、CPU使用率过高、磁盘I/O过多等运行时的性能问题。
- 不能检查算法效率:Cppcheck不能检查代码中使用的算法的效率。例如,如果你使用了一个O(n^2)的算法,而有一个O(n log n)的算法可以完成同样的任务,Cppcheck无法检测这个问题。
- 不能检查并发问题:Cppcheck不能检查并发问题,例如死锁、竞态条件等。这些问题通常需要动态分析工具或专门的并发分析工具来检查。
如果你需要进行深入的性能分析,你可能需要使用专门的性能分析工具,如gprof,Valgrind的Callgrind,或者Intel VTune等。
自定义检测规则
方式一(过滤检测规则)
使用 --suppress
选项过滤特定的警告:
如果你想要忽略某些警告,可以在命令行中使用 --suppress
选项。例如,如果你想要忽略所有的“缺少头文件”的警告,可以使用以下命令:
cppcheck --suppress=missingInclude ./
这里,“missingInclude” 是要忽略的警告类型。将其替换为您希望过滤掉的警告类型。
方式二(筛选检测结果)
在 CppCheck 运行结束后,使用自定义脚本对输出结果进行过滤。例如,您可以使用 Python 编写一个脚本,读取 CppCheck 的输出,然后根据自定义规则筛选警告信息。以下是一个简单的示例:
import subprocess
import sys
def main():
cppcheck_command = "cppcheck --enable=all --xml --xml-version=2 ./"
result = subprocess.run(cppcheck_command.split(), capture_output=True, text=True)
# 在这里添加自定义规则
def custom_filter(error):
# 示例规则:过滤所有包含特定文件名的警告
return "my_special_file.cpp" not in error
# 添加更多规则
def custom_filter_2(error):
# 示例规则:过滤所有包含特定错误类型的警告
return "error type" not in error
# 将所有规则放入一个列表中
filters = [custom_filter, custom_filter_2]
# 对每个规则进行过滤
filtered_errors = result.stderr.splitlines()
for filter_func in filters:
filtered_errors = list(filter(filter_func, filtered_errors))
for error in filtered_errors:
print(error)
if __name__ == "__main__":
main()
这段代码的主要步骤如下:
cppcheck_command = "cppcheck --enable=all --xml --xml-version=2 ./"
:这行代码定义了一个字符串,这个字符串是要执行的命令。这个命令会调用cppcheck工具,--enable=all
表示启用所有的检查,--xml
表示输出结果为XML格式,--xml-version=2
表示使用XML的版本2,./
表示对当前目录下的所有文件进行检查。result = subprocess.run(cppcheck_command.split(), capture_output=True, text=True)
:这行代码使用Python的subprocess模块来执行上面定义的命令。cppcheck_command.split()
将命令字符串分割成一个列表,capture_output=True
表示捕获命令的输出,text=True
表示将输出作为文本处理。custom_filter
和custom_filter_2
函数:这两个函数是自定义的过滤规则,它们都接收一个错误信息作为参数,如果错误信息满足某种条件(例如包含特定的文件名或错误类型),则返回False,否则返回True。这样就可以过滤掉不想看到的错误信息。filters = [custom_filter, custom_filter_2]
:这行代码将所有的过滤函数放入一个列表。filtered_errors = result.stderr.splitlines()
:这行代码将cppcheck的错误输出分割成多行。for filter_func in filters:
:这个循环对每个过滤函数进行迭代。filtered_errors = list(filter(filter_func, filtered_errors))
:这行代码使用Python的filter函数和当前的过滤函数来过滤错误信息。- 最后,对过滤后的错误信息进行迭代并打印。
总的来说,这段代码的目的是运行cppcheck工具,获取其错误输出,然后根据一些自定义的规则来过滤错误信息。
方式三(--rule和--rule-file选项 增加正则表达式规则)
cppcheck
是一个C和C++代码的静态分析工具,它可以检查代码中的错误,包括语法错误、未使用的函数、内存泄漏、未初始化的变量等。cppcheck
还支持用户自定义规则,这是通过--rule
和--rule-file
选项实现的。
--rule
选项允许你直接在命令行中定义一个规则。规则是一个正则表达式,用于匹配你想要检查的代码模式。例如,如果你想检查所有的printf
函数调用,你可以使用以下命令:
cppcheck --rule="printf" myfile.cpp
这将会检查myfile.cpp
文件中所有的printf
函数调用。
--rule-file
选项允许你从一个文件中读取规则。这个文件应该包含一个或多个规则,每个规则一行。例如,如果你有一个名为rules.txt
的文件,其中包含以下规则:
printf
scanf
你可以使用以下命令应用这些规则:
cppcheck --rule-file=rules.txt myfile.cpp
这将会检查myfile.cpp
文件中所有的printf
和scanf
函数调用。
注意,cppcheck
的规则是正则表达式,所以你可以使用正则表达式的所有功能来定义你的规则。例如,你可以使用.*
来匹配任何字符,[a-z]
来匹配任何小写字母,等等。
最后,cppcheck
的规则检查是大小写敏感的,所以printf
和Printf
是两个不同的规则。如果你想忽略大小写,你可以使用正则表达式的i
标志,例如(?i)printf
将会匹配printf
、Printf
、PRINTF
等等。
rule自定义规则示例
以下是一些可能的Cppcheck自定义规则的例子:
- 检查是否存在使用
malloc
而不是new
的代码:bash malloc\(
这个规则会匹配到任何使用malloc
函数的代码。在C++中,通常推荐使用new
而不是malloc
,因为new
会自动调用对象的构造函数。 - 检查是否存在使用
printf
而不是cout
的代码:bash printf\(
这个规则会匹配到任何使用printf
函数的代码。在C++中,通常推荐使用cout
而不是printf
,因为cout
是类型安全的。 - 检查是否存在未使用的变量:
bash int\s+\w+;
这个规则会匹配到任何定义了一个整数变量但没有使用它的代码。未使用的变量可能是一个错误的信号,因为它可能意味着你忘记了使用这个变量。 - 检查是否存在使用
delete
但没有将指针设为nullptr
的代码:bash delete\s+\w+;\s*(?!.*\1\s*=\s*nullptr;)
这个规则会匹配到任何使用delete
但没有将指针设为nullptr
的代码。在C++中,删除一个指针后,通常推荐将其设为nullptr
,以防止悬挂指针。 - 检查是否存在没有虚析构函数的多态基类:
bash class\s+\w+\s*{\s*(public|protected):\s*virtual\s+\w+\s*\(\)\s*;\s*(?!.*virtual\s+~\1\(\)\s*;)
这个规则会匹配到任何定义了虚函数但没有虚析构函数的类。在C++中,多态基类应该总是有一个虚析构函数,以防止在删除派生类对象时出现未定义的行为。 - 检查是否存在使用
std::endl
而不是\n
的代码:bash std::cout\s*<<\s*.*std::endl
这个规则会匹配到任何使用std::endl
的代码。在C++中,std::endl
不仅会插入一个换行符,还会刷新输出流。如果你不需要立即刷新输出流,使用\n
可能会更高效。
请注意,这些规则可能会产生一些误报,因为它们可能会匹配到一些合法的代码。如果你需要更精确的检查,你可能需要创建一个更复杂的正则表达式,或者使用一个更高级的静态代码分析工具。
在其他环境安装cppcheck插件
QtCreator
在Qt Creator中添加Cppcheck工具的步骤如下:
- 启动Qt Creator:首先,打开你的Qt Creator IDE。
- 打开工具选项:在菜单栏中,选择 "工具" -> "选项"。
- 进入外部工具设置:在弹出的选项窗口中,选择 "外部工具"。
- 添加新的外部工具:点击 "添加" 按钮,创建一个新的外部工具配置。
- 配置外部工具:在新的外部工具配置中,填写以下信息:
- 执行:输入你的Cppcheck执行文件的路径。例如,如果你在Linux下安装了Cppcheck,这个路径可能是
/usr/bin/cppcheck
。在Windows下,这个路径可能是你的Cppcheck安装目录下的cppcheck.exe
文件。 - 参数:输入
--enable=all %{CurrentProject:Path}
。这个参数会让Cppcheck检查当前项目的所有代码,并启用所有的检查。 - 工作目录:输入
%{CurrentProject:Path}
。这个设置会让Cppcheck在当前项目的目录下运行。
- 保存配置:点击 "应用" 或 "确定" 按钮,保存你的配置。
- 使用Cppcheck:现在,你可以在 "工具" -> "外部" -> "Cppcheck" 中运行Cppcheck了。
Visual Studio
以下是在Visual Studio 2019和2022中安装Cppcheck的步骤:
- 下载Cppcheck
首先,你需要下载Cppcheck。你可以从其官方GitHub页面(https://github.com/danmar/cppcheck)下载最新版本的Cppcheck。 - 安装Cppcheck
下载完成后,运行安装程序并按照提示进行安装。记住你安装Cppcheck的路径,因为你稍后需要在Visual Studio中使用它。 - 下载和安装Visual Studio插件
接下来,你需要下载并安装Cppcheck的Visual Studio插件。你可以从Visual Studio Marketplace(https://marketplace.visualstudio.com/items?itemName=MatthewManela.CppcheckforVisualStudio
)下载插件。在Visual Studio中,点击"Extensions"(扩展)菜单,然后选择"Manage Extensions"(管理扩展)。在打开的窗口中,点击"Online"(在线),然后在搜索框中输入"Cppcheck"。找到"Cppcheck for Visual Studio",点击"Download"(下载)。
下载完成后,重启Visual Studio以完成插件的安装。 - 配置Cppcheck
插件安装完成后,你需要配置Cppcheck。在Visual Studio中,点击"Tools"(工具)菜单,然后选择"Options"(选项)。在打开的窗口中,找到"Cppcheck",然后在"Cppcheck path"(Cppcheck路径)中输入你之前安装Cppcheck的路径。 - 使用Cppcheck
现在,你可以开始使用Cppcheck了。在Visual Studio中,右键点击你的项目,然后选择"Run Cppcheck"(运行Cppcheck)。Cppcheck将开始分析你的代码,并在"Error List"(错误列表)窗口中显示结果。
Vs code
在VS Code中安装和使用Cppcheck,你可以按照以下步骤操作:
- 下载并安装Cppcheck
首先,你需要下载并安装Cppcheck。你可以从其官方GitHub页面(https://github.com/danmar/cppcheck )下载最新版本的Cppcheck。下载完成后,运行安装程序并按照提示进行安装。记住你安装Cppcheck的路径,因为你稍后需要在VSCode中使用它。 - 安装Cppcheck插件
打开VS Code,点击左侧边栏的Extensions图标(或者使用快捷键Ctrl+Shift+X)打开Extensions视图。在搜索框中输入"Cppcheck",找到Cppcheck插件并点击Install按钮进行安装。 - 配置Cppcheck
插件安装完成后,你需要配置Cppcheck。点击左侧边栏的Settings图标(或者使用快捷键Ctrl+,)打开Settings视图。在搜索框中输入"Cppcheck",找到Cppcheck的设置项。在"Cppcheck Path"设置项中,输入你之前安装Cppcheck的路径。 - 使用Cppcheck
配置完成后,你可以开始使用Cppcheck了。在VS Code中,右键点击你的代码文件,然后选择"Run Cppcheck"。Cppcheck将开始分析你的代码,并在"Problems"窗口中显示结果。
Cppcheck的局限性
Cppcheck是一个非常有用的工具,它可以检测C++代码中的许多常见错误和潜在问题。然而,像所有工具一样,Cppcheck也有其局限性。以下是一些主要的局限性:
- 无法检测所有类型的错误:虽然Cppcheck可以检测许多类型的错误,但它不能检测所有类型的错误。例如,它无法检测逻辑错误,这种错误只能通过仔细的代码审查和测试来发现。
- 可能存在误报和漏报:Cppcheck可能会误报一些不存在的问题,或者漏报一些实际存在的问题。这是因为Cppcheck主要依赖于静态分析,而静态分析的准确性受到许多因素的影响,包括代码的复杂性、使用的编程语言特性等。
- 无法处理非标准的C++特性:Cppcheck是基于标准C++的,因此,如果你的代码使用了非标准的C++特性,Cppcheck可能无法正确处理。
- 无法理解复杂的语义:Cppcheck主要通过语法和简单的语义分析来检测错误,但它无法理解复杂的语义。例如,如果一个函数的行为依赖于它的输入参数的某些特性,Cppcheck可能无法正确理解这种依赖关系。
- 无法分析运行时行为:Cppcheck是一个静态分析工具,它只能分析代码的文本,而不能分析代码的运行时行为。因此,它无法检测运行时错误,如竞态条件、死锁等。
- 无法分析动态内存管理:虽然Cppcheck可以检测一些基本的内存管理错误,如内存泄漏,但它无法分析复杂的动态内存管理问题,如内存碎片化。
- 无法分析库函数的行为:Cppcheck无法分析库函数的内部行为。因此,如果你的代码依赖于库函数的某些特性,Cppcheck可能无法正确检测相关的问题。
总的来说,虽然Cppcheck是一个非常有用的工具,但它不能替代其他的代码审查和测试工具。你应该将Cppcheck作为你的工具箱中的一个工具,而不是唯一的工具。
源码框架
Cppcheck使用C++语言编写。Cppcheck的主要入口是cppcheck.cpp文件,该文件定义了Cppcheck类,并包含了Cppcheck的主要逻辑。Cppcheck类是Cppcheck的核心类,负责整个工具的控制流程和数据处理。
Cppcheck的主要工作过程简单分为:
(1) 解析源代码: Cppcheck首先通过Parser类,解析输入的C/C++源文件,构建抽象语法树(AST);
(2) 对AST进行遍历: Cppcheck通过调用ASTVisitor类对AST进行遍历,可以访问和处理AST中的各个节点,比如函数、变量、语句等;
(3) 检查语义错误: Cppcheck通过调用各种规则类,对AST中的节点进行语义检查。规则类是Cppcheck中定义具体规则的地方,每个规则类都会继承自Rule类,并实现一系列方法进行具体的规则检查;
(4) 保存错误信息: 在检查过程中,如果发现了错误,Cppcheck会将错误信息保存在ErrorLogger类中,以便后续的输出和展示;
(5) 输出结果: 最后,Cppcheck会将错误信息输出到屏幕、文件等。
在Cppcheck源码中,Parser类负责解析源代码文件,将代码生成抽象语法树。Cppcheck通过遍历ASTVisitor类来对AST进行遍历,可以访问和处理各种节点。通过继承ASTVisitor类,可以轻松实现对AST中节点的访问和处理。
规则类是Cppcheck中定义具体规则的地方,每个规则类都继承自Rule类,并实现了一系列用于规则检查的方法。每个规则类都会实现一个或者多个检查方法,用于检查AST中特定节点是否满足规则。当Cppcheck遍历AST时,会逐个调用规则类的检查方法,以发现代码中的错误。
在Cppcheck源码中,有一个叫做ErrorLogger的类,负责保存错误信息。当检查过程中发现错误时,会调用ErrorLogger类的方法将错误信息保存下来,以便后续的输出和展示。
在Cppcheck的源码中,还包含了一些其他的辅助类和函数,用于辅助实现Cppcheck的各项功能。比如,Preprocessor类负责预处理源代码,Token类用于表示源代码中的各种标记,如变量、函数等。这些类和函数相互协作,共同完成Cppcheck的工作。
总结:Cppcheck是一个非常强大的C/C++静态代码分析工具,通过解析源代码,构建抽象语法树,并对AST进行遍历和处理,最终发现代码中的潜在问题和错误。
检查器列表
版本“2.12.1”
# get list of checks
cppcheck --doc
cppcheck / Wiki / ListOfChecks
64-bit portability
检查是否存在64位可移植性问题:
- 将地址分配给int/long
- 从函数返回时将地址从/转换为整数
Assert
如果assert语句中存在副作用(side effects),则发出警告(因为这会导致调试/发布版本中的不同行为)。
Auto Variables
指向变量的指针只有在变量在作用域内时才有效。
检查:
-返回指向自动变量或临时变量的指针
-将变量的地址分配给函数的有效参数
-返回对本地/临时变量的引用
-函数参数的返回地址
-指针参数的可疑赋值
-函数参数的无用赋值
Boolean
布尔类型检查
-对布尔值使用增量(increment )
-布尔表达式与0或1以外的整数的比较
-使用关系运算符返回布尔值的函数的比较
-使用关系运算符比较布尔值和布尔值
-在位运算表达式中使用bool
-在条件中添加指针(忘记了取消引用或需要指针溢出来使条件为false)
-将布尔值分配给指针或浮点
-从具有布尔返回值的函数返回0或1以外的整数
Boost usage
检查Boost的无效使用情况:
-BOOST_FOREACH期间的容器修改
Bounds checking
越界检查:
-数组索引越界(Array index out of bounds)
-指针计算溢出(Pointer arithmetic overflow)
-缓冲区溢出(Buffer overflow)
-strncat()的危险用法
-在检查之前使用数组索引
-导致缓冲区非零终止的部分字符串写入。
-检查传递给函数的数组是否足够大
-正在分配负大小的内存
Check function usage
检查函数使用情况:
-非void函数中缺少“return”
-未使用的某些函数的返回值
-函数的输入值无效
-如果调用了不鼓励使用的函数,则发出警告
-memset()第三个参数为零
-值超出范围的memset()作为第二个参数
-将浮点值作为第二个参数的memset()
-针对std::move影响的返回值的复制省略优化(copy elision optimization for returning value affected by std::move)
-使用memcpy()/memset()而不是for循环
Class
检查每个类的代码。
-缺少构造函数和拷贝构造函数
-应该显式的构造函数
-所有变量都由构造函数初始化了吗?
-是否所有变量都由“operator=”分配?
-如果在类上使用memset、memcpy等,则发出警告
-如果类的内存是用malloc()分配的,则发出警告
-如果是基类,请检查析构函数是否为虚拟的
-是否有未使用的私有函数?
-'operator='应检查是否分配给self
-成员方法的Constness
-初始化顺序(Order of initializations)
-建议使用初始化列表
-成员自身的初始化
-“this”的可疑减法
-构造函数/析构函数中纯虚函数的调用
-重复的继承数据成员
-检查公共接口的任意使用是否不会导致除以零
-删除“self-pointer”,然后访问“this”
-检查重写(overriding)虚拟函数时是否使用了“override”关键字
-检查“一个定义规则”是否为中提琴(viola)
Condition
将条件与指定和其他条件匹配(Match conditions with assignments and other conditions:):
-分配(assignment )和比较不匹配=>比较总是真/假
-比较中lhs和rhs不匹配=>比较总是真/假
-检测|的使用情况,其中&应该使用(Detect usage of | where & should be used)
-重复的条件和分配(assignment)
-检测匹配的“if”和“else-if”条件
-bitand 不匹配(a &= 0xf0;a &= 1;=> a = 0)
-相反的内部条件总是错误的
-提前退出后的相同条件总是错误的
-总是正确/错误的条件
-互斥 || 总是评估为true
-总是正确/错误的模(modulo )结果的比较。
-已知变量值=>条件始终为真/假
-溢出测试无效。一些主流编译器在优化代码时会删除此类溢出测试。
-condition=>条件中容器/迭代器的可疑赋值始终为true。
Exception Safety
Checking exception safety
- Throwing exceptions in destructors
- Throwing exception during invalid state
- Throwing a copy of a caught exception instead of rethrowing the original exception
- Exception caught by value instead of by reference
- Throwing exception in noexcept, nothrow(), attribute((nothrow)) or __declspec(nothrow) function
- Unhandled exception specification when calling function foo()
- Rethrow without currently handled exception
检查异常安全
-在析构函数中引发异常
-在无效状态下引发异常
-引发捕获的异常的副本,而不是重新引发原始异常
-由值而非引用捕获的异常
-在noexcept、nothrow()、attribute((nothrow))或__declspec(nothrrow)函数中引发异常
-调用函数foo()时未处理的异常规范
-在没有当前处理的异常的情况下重试
IO using format string
检查格式字符串输入/输出操作。
-函数“sprintf”使用不当(数据重叠)
-“scanf”格式字符串中缺少或错误的宽度说明符
-使用已关闭的文件
-未定位的文件输入/输出会导致未定义的行为
-读取到仅为写入而打开的文件(反之亦然)
-对以追加模式打开的文件执行重新定位操作
-同一个文件不能在不同的流上同时打开进行读写
-对输入流使用fflush()
-输出流的使用无效。例如:“std::cout<std::cout;”
-给“printf”或“scanf;”的参数数目错误
Leaks (auto variables)
当自动变量已分配但未解除分配或两次解除分配时进行检测。
Memory leaks (address not taken)
Not taking the address to allocated memory
Memory leaks (class variables)
如果构造函数分配内存,那么析构函数必须将其释放。
Memory leaks (function variables)
Is there any allocated memory when a function goes out of scope
Memory leaks (struct members)
Don't forget to deallocate struct members
Null pointer
Null pointers
- null pointer dereferencing
- undefined null pointer arithmetic
Other
Other checks
- division with zero
- 作用域对象在构造后立即销毁
- assert语句中的赋值
- free() or delete of an 无效的内存位置
- 带负右操作数的位运算
- overlapping write of union
-将getc()、fgetc()和getchar()的返回值强制转换为字符,并将其与EOF进行比较
-InterlockedDecrement()调用后具有非互锁访问的竞争条件
-表达式'x=x++;'取决于副作用(side effects)的评估顺序
-要么除以零,要么无效
-访问已移动或已转发的变量。
-const变量的冗余数据复制
-变量或缓冲区的后续赋值或复制
-按值传递参数
-将NULL指针传递给参数数量可变的函数会导致UB。
-C++代码中的C样式指针强制转换
-在不兼容的指针类型之间强制转换
-语句不完整
-检查如何使用带符号的char变量
-可变范围可能受到限制
-不同寻常的指针运算。例如:“abc”+“d”
- redundant assignment, increment, or bitwise operation in a switch statement
- redundant strcpy in a switch statement
- Suspicious case labels in switch()
-变量对自身的赋值
-总是导致正确或错误的值的比较
- Clarify calculation with parentheses
- suspicious comparison of '\0' with a char* variable
- duplicate break statement
-不可达(unreachable )代码
-测试无符号变量是否为负/正
-可疑使用;在“if/for/while”语句的末尾。
-使用memset/memcpy/memmove未完全填充数组。
-算术表达式中使用的NaN(不是数字)值。
-return语句中的逗号(逗号很容易被误读为分号)。
-优选erfc、expm1或log1p以避免精度损失。
-if/else或三元运算符的两个分支中的相同代码。
-指针上的冗余指针操作,如&*some_ptr。
-查找未使用的“goto”标签。
-函数声明和定义参数名称不同。
-函数声明和定义参数的顺序不同。
-shadow变量。
-变量可以声明为const。
-计算1的模。
- known function argument,计算可疑。
STL usage
检查STL的无效使用:
-越界错误
-遍历容器时迭代器的误用
-调用中的容器不匹配
-调用中的相同迭代器
-取消引用已擦除(erased )的迭代器
-对于vectors:使用push_back后使用迭代器/指针
-优化:使用empty()而不是size()来保证快速代码
-使用find时出现可疑情况
-在关联容器中进行不必要的搜索
-冗余条件
-common mistakes when using string::c_str()
-对字符串和STL函数的无用调用
-取消引用无效迭代器
-从空STL容器中读取
-在空STL容器上迭代
-考虑使用STL算法而不是原始循环
-使用互斥锁的错误locking
Sizeof
sizeof() usage checks
- sizeof for array given as function argument
- sizeof for numeric given as function argument
- using sizeof(pointer) instead of the size of pointed data
- look for 'sizeof sizeof ..'
- look for calculations inside sizeof()
- look for function calls inside sizeof()
- look for suspicious calculations with sizeof()
- using 'sizeof(void)' which is undefined
String
Detect misusage of C-style strings:
- overlapping buffers passed to sprintf as source and destination
- incorrect length arguments for 'substr' and 'strncmp'
- suspicious condition (runtime comparison of string literals)
- suspicious condition (string/char literals as boolean)
- suspicious comparison of a string literal with a char* variable
- suspicious comparison of '\0' with a char* variable
- overlapping strcmp() expression
Type
Type checks
- bitwise shift by too many bits (only enabled when --platform is used)
- signed integer overflow (only enabled when --platform is used)
- dangerous sign conversion, when signed value can be negative
- possible loss of information when assigning int result to long variable
- possible loss of information when returning int result as long return value
- float conversion overflow
Uninitialized variables
Uninitialized variables
- using uninitialized local variables
- using allocated data before it has been initialized
Unused functions
Check for functions that are never called
UnusedVar
UnusedVar checks
- unused variable
- allocated but unused variable
- unread variable
- unassigned variable
- unused struct member
Using postfix operators
Warn if using postfix operators ++ or -- rather than prefix operator
Vaarg
Check for misusage of variable argument lists:
- Wrong parameter passed to va_start()
- Reference passed to va_start()
- Missing va_end()
- Using va_list before it is opened
- Subsequent calls to va_start/va_copy()
错误信息列表
# get list of error messages
cppcheck --errorlist