当前位置: 首页 > 科技观察

静态分析工具ClangStaticAnalyzer(三)Cppcheck

时间:2023-03-20 20:56:12 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.com之前的介绍在使用CodeChecker的时候,用到了Cppcheck。让我们来看看这个工具是什么以及如何使用它。一、Cppcheck简介Cppcheck是C/C++代码的静态分析工具。它提供独特的代码分析技术来检测缺陷,不检查代码中的语法错误,只检查编译器无法检测到的缺陷,重点检测未定义的行为错误和危险的编码结构。它的目标是减少误报、零误报,并检查代码中的真正错误。Cppcheck旨在能够分析C/C++代码,即使它具有非标准语法(在嵌入式项目中很常见)。Cppcheck有开源版本和具有扩展功能和支持的Cppcheck高级版本。有关商业版本的更多信息和购买选项,请访问www.cppchecksolutions.com。(1)Cppcheck独有的代码分析,可以检测代码中的各种错误。命令行界面和图形用户界面均可用。Cppcheck非常专注于检测未定义的行为。(2)Cppcheck特定的分析技术使用多个静态分析工具可能是个好主意,每个工具都具有独特的功能特性。这已在研究中得到证实。那么Cppcheck有什么独特之处呢?cppcheck使用不健全的过程敏感分析,其他几个分析器使用基于抽象解释的路径敏感分析,也不错,但有利也有弊。从理论上讲,根据定义,路径敏感分析优于流量敏感分析。但实际上,这意味着Cppcheck将检测到其他工具无法检测到的错误。在Cppcheck中,数据流分析不仅是“正向的”,而且是“双向的”。大多数分析器都会对此进行诊断,并确定在数组索引1000处发生了溢出。voidfoo(intx){intbuf[10];如果(x==1000)buf[x]=0;//<-ERROR}cppcheck也会诊断这个问题,当x等于1000时,赋值也会发生数组越界。voidfoo(intx){intbuf[10];缓冲区[x]=0;//<-ERRORif(x==1000){}}(3)未定义行为死指针除以零整数溢出零无效位移操作数无效转换无效转换无效使用STLSTL无效内存管理内存管理空指针解引用空指针解引用越界检查未初始化变量写入常量数据写入常量数据2.Cppcheck安装Cppcheck也可以从各种包管理器安装;但是,您最终可能会得到一个过时的版本。为了获得更新版本,您可以访问https://github.com/danmar/cppcheck进行源码安装。Debian:sudoapt-getinstallcppcheckFedora:sudoyuminstallcppcheckmacOS:brewinstallcppcheck3.开始第一个测试程序,这里是一个简单的代码,我们命名为file1.c。intmain(){字符a[10];[10]=0;return0;}执行cppcheckfile1.c,输出如下:zhushangyuan@DESKTOP-RPE9R4O:~/CSA$cppcheckfile1.cCheckingfile1.c...[file1.c:4]:(error)Array'a[10]'在索引10处访问,这是越界的。让我们再次尝试上面的示例并将其保存到file2.c。voidfoo(intx){intbuf[10];缓冲区[x]=0;//<-错误1??if(x==1000){buf[x]=0;//<-ERROR2}}执行cppcheck--enable=allfile2.c,输出如下。可以看出有2个warning和3个style问题。zhushangyuan@DESKTOP-RPE9R4O:~/CSA$cppcheck--enable=allfile2.cCheckingfile2.c...file2.c:4:6:warning:条件'x==1000'是多余的或者数组'buf[10]'在索引1000处被访问,这是越界的。[arrayIndexOutOfBoundsCond]buf[x]=0;//<-ERROR1^file2.c:5:9:注意:假设条件'x==1000'不是多余的if(x==1000){^file2.c:4:6:注意:数组索引越界buf[x]=0;//<-ERROR1^file2.c:6:8:警告:条件'x==1000'是多余的,或者数组'buf[10]'在索引1000处被访问,这是越界的。[arrayIndexOutOfBoundsCond]buf[x]=0;//<-ERROR2^file2.c:5:9:注意:假设条件'x==1000'不是多余的if(x==1000){^file2.c:6:8:注意:数组索引越界buf[x]=0;//<-ERROR2^file2.c:4:10:style:变量'buf[x]'被分配了一个从未使用过的值。[未读变量]buf[x]=0;//<-ERROR1^file2.c:6:12:style:变量'buf[x]'被分配了一个从未使用过的值。[未读变量]buf[x]=0;//<-ERROR2^file2.c:1:0:风格:从未使用函数“foo”。[unusedFunction]^(1)检查文件夹Cppcheck支持检查文件夹中的所有文件通常一个项目会有很多源文件,如果需要同时检查,Cppcheck可以检查一个文件夹中的所有文件。如果path是一个文件夹,cppcheck将递归检查该文件夹中的所有源文件。cppcheck路径示例输出如下:zhushangyuan@DESKTOP-RPE9R4O:~/CSA$cppcheck.Checkingfile1.c...file1.c:4:4:error:Array'a[10]'accessedatindex10,这是越界的。[arrayIndexOutOfBounds]a[10]=0;^1/4文件已检查12%正在检查file2.c...2/4文件已检查38%正在检查hello.c...hello.c:2:13:错误:被零除。[zerodiv]intx=7/0;//bug^3/4fileschecked50%doneCheckingsimple.c...simple.c:16:11:error:除以零。[zerodiv]返回5/(x-x);//警告^simple.c:12:5:错误:未初始化的变量:s[uninitvar]f(s);//警告^simple.c:12:5:错误:未初始化的结构成员:s.x[uninitStructMember]f(s);//warn^4/4fileschecked100%done(2)ManuallycheckfilesoruseprojectfilestouseCppcheck您可以通过指定要检查的文件/文件夹和设置来手动检查文件,也可以使用项目文件(cmake/视觉工作室)。使用项目文件速度更快,因为它只需要很少的配置。手动检查文件可以更好地控制分析。不一定哪种方法效果最好,建议尝试一下,你可能会得到不同的结果,大多数bug需要使用这两种方法。4.SeveritylevelSeverities输出信息中的severitylevel支持以下类型:errorerrorwhencodeexecutedthereeitherundefinedbehaviororothererror,suchasamemoryleakorresourceleak。Foundundefinedbehaviororothererrors,suchasmemoryleaks,resourceleakswarningalarmwhencodeexecutedtheremightbeundefinedbehaviormayhaveundefinedbehaviorstylestylestyle文体问题,如未使用的函数,冗余代码,constness,operatorprecedence,可能的错误。样式问题,例如未使用的行数、冗余代码、常量、运算符优先级、可能的错误等基于常识的性能性能运行时性能建议,尽管不确定通过修复这些消息是否会实现任何可测量的速度差异.这些建议仅基于常识,即使您修复了这些消息,也不确定您是否会获得任何可衡量的性能提升。便携性便携性警告。实现定义的行为。64位可移植性。一些未定义的行为可能会“随心所欲”地工作,等等。可移植性警告。64位可移植性,代码在不同的编译器中运行可能不同。information信息配置问题,与语法正确性无关,但使用的cppcheck配置可以改进。配置问题,建议在配置时只启用这些(1)启用消息默认情况下,只显示错误消息,可以通过--enable命令启用更多检查。启用警告消息:cppcheck--enable=warningfile.c启用性能消息:cppcheck--enable=performancefile.c启用信息消息:cppcheck--enable=informationfile.c出于历史原因启用警告--enable=style,性能、便携性和样式信息。当使用旧的XML格式时,这些由样式指示:cppcheck--enable=stylefile.c启用警告和性能消息:cppcheck--enable=warning,performancefile.c启用未使用的功能检查。这不能通过--enable=style启用,因为它不能与库一起正常工作。cppcheck--enable=unusedFunctionfile.cEnableallmessages:cppcheck--enable=all5.常见错误修改隐式构造问题。示例:(样式)“Slice”类有一个带有1个非显式参数的构造函数。解决方法:在Slice构造函数前添加explicit,使其成为显示构造的必要条件。当然,这有时并不一定要显示构造。变量未初始化问题。示例:(警告)成员变量“TableFileCreationInfo::file_size”未在构造函数中初始化。解决方法:在构造函数中加入变量初值。变量/函数未使用的问题。示例:(样式)未使用的变量:输出。示例:(样式)从未使用函数“rocksmt_wal_iter_status”。解决方法:考虑以后是否还需要,及时删除不需要的,保留需要的。原始循环问题。示例:(样式)考虑使用std::fill算法而不是原始循环。[使用Stl算法]。示例:(样式)考虑使用std::transform算法而不是原始循环。[使用Stl算法]。解决方法:用STL标准库算法函数替换loopconvenience。通过引用问题。示例:(性能)函数参数“f”应通过引用传递。解决方法:声明函数时,如果可以引用传递,尽量使用引用传递,尽量避免值传递。const参数问题。示例:(性能)函数参数“s”应通过常量引用传递。[传递值]。解决方法:在形参s前加上const,函数中没有被修改的变量尽量声明为const。了解更多开源知识,请访问:开源基础软件社区https://ost.51cto.com。