静态检查工具cppcheck

      

1 Cppcheck简介

CppCheck是一个静态代码检查工具。在众多的静态代码检查工具中cppcheck是一款较为优秀的工具。它简单、开源、免费、功能强大,值得推广和使用。

CppCheck对产品的源代码执行严格的逻辑检查。执行的检查包括: 

  •         自动变量检查
  •         代码格式错误,以及性能因素检查
  •         异常 STL 函数使用检查
  •         操作系统资源释放检查,中断.文件描述符等
  •         内存泄漏检查,主要是通过内存引用指针
  •         异常内存使用,释放检查
  •         过期的函数,废弃函数调用检查
  •         class类检查
  •         数组的边界检查

2 Cppcheck安装

        2.1 linux下安装

Ubuntu终端窗口输入:sudo apt-get install cppcheck

        2.2 windows下安装

Cppcheck - A tool for static C/C++ code analysis下载安装文件,安装即可

3 Cppcheck检查内存泄露

           3.1对局部变量分配内存检查

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

void malloc_test1(){
    cout << " malloc 10 bytes" << endl;
    char *s = (char *)malloc(10 * sizeof(char));
    strcpy(s, "abcd");
}

void malloc_test2(){
    cout << " malloc 4 bytes for int" << endl;
    int *data = (int *)malloc( sizeof(int));
    *data = 2;
    
}

void new_test1(){
    cout << " new_test1 " << endl;
    int *p = new int;
    *p = 1;
}

void new_test2(){
    cout << " new_test2 " << endl;
    int *pdata;
    pdata = new int [8];
    pdata[0] = 2;
    delete pdata;
}

int main()
{
    malloc_test1();
    malloc_test2();
    new_test1();
    new_test2();

    return 0;
}

Leak.cpp有四处内存泄漏,用cppcheck检查,在终端输入:cppcheck leak.cpp

四处泄漏的地方全都找到了!

        3.2 对全局变量分配内存检查

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

int *g_buff = NULL;

void malloc_test(){
    cout << " malloc 10 bytes" << endl;
    g_buff = (int *)malloc(10 * sizeof(int));
    g_buff[0]= 10;
	printf("g_buff[0] %d\n", g_buff[0]);
}
int main()
{
    malloc_test();
    return 0;
}

输入cppcheck global_leak.cpp, 没有查到内存泄漏。

        3.3 A函数分配B函数释放

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

int *g_buff = NULL;

int *fa(){
	
	int *p = new int;
	*p = 1;

}
void fb(int *p){
	delete p;
}
int main()
{
    int *data = fa();
	fb(data);
    return 0;
}

输入cppcheck ab_leak.cpp, 报告有内存泄露,实际上没有内存泄露。

        3.4 小结

Cppcheck能查到部分内存泄漏,但是查不到全局变量内存泄漏,有时候可能会误报。

4 内存越界检查

        4.1 堆缓冲区溢出

// overflow.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, const char *argv[]) {

    char *s = (char*)malloc(4 * sizeof(char));
    printf("s address = %p\n",s);
    strcpy(s, "Hello");
    printf("string is: %s\n", s);
    free(s);

    return 0;
}

检查结果,发现内存越界。

        4.2 栈缓冲区溢出

                4.2.1上溢

#include <stdio.h>
#include <unistd.h>

#define N 10
void test(){
	int arr[N];
	arr[10] = 1;
}
int main() {

    int stack_array[100];

    printf("stack overflow1..\n");
    stack_array[101] = 1;
    printf("stack overflow2..\n");

	test();
    return 0;
}

检查结果,发现内存越界。

                4.2.2下溢

#include <iostream>
#include <stdint.h>
 #include <stdio.h>
using namespace std;
 
int main()
{
    char p[5] = "abc";
    uint8_t tmp = 5;
    int a = 1;
    int b = 2;
    int c = 3;
    char c1 = '1';
    char c2 = '2';
    char c3 = '3';

    p[-1] = 7;
 
    cout << "out of bound " << endl;
    cout << "*p = " <<(void*)p << endl;
 
    cout << "&temp "<< (void*)&tmp << endl;
    printf("a address %p\n", &a);
    printf("b address %p\n", &b);
    printf("c address %p\n", &c);
    printf("c1 address %p\n", &c1);
    printf("c2 address %p\n", &c2);
    printf("c3 address %p\n", &c3);
 
    cout << " tmp ="<< (uint32_t)tmp << endl;
 
    return 0;
}

检查结果,发现内存越界。

        4.3 较为复杂的内存越界

// overflow.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
char *get_mem(){
	
	char *buff= (char*)malloc(4 * sizeof(char));
	return buff;
}
void use_mem(char *text){
	
	strcpy(text,"abcde");
	printf("text= %s\n",text);
	
	free(text);
	
}
int main(int argc, const char *argv[]) {

    
	char *data = get_mem();
	use_mem(data);

    return 0;
}

在这个例子中,get_mem()分配内存,use_mem使用内存,发现了越界。Cppcheck检查结果:

cppcheck没能发现内存越界。

        4.4 小结

在检查内存越界问题上,在一个函数里声明、分配使用,cppcheck能查出越界问题,如果不是一个函数里使用,就容易出现漏报。

5 内存释放后又使用

#include <stdio.h>
#include <malloc.h>

int main() 
{
        int *p = NULL;
        printf("use after free\n");
        p = (int *)malloc(10 * sizeof(int));
        free(p);
        *p = 3;
        return 0;
}

检查结果:

6 对空指针进行写操作



#include <stdio.h>

#include <string.h>

int fun(){
	char *p = NULL;
	strcpy(p,"a");
	return 0;
}

int main(int argc, const char *argv[]) {
	printf("write null\n");
    fun();
    return 0;
}

检查结果:

7 遗漏文件描述符


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

void read_file(){
	char buff[10]={0};
	FILE *fp = fopen("test.txt", "r"); 
    if (fp == NULL) {  
        perror("Open file recfile");
        exit(1);  
    }  
    fread(buff, 1, 10, fp);  
    printf("buff:%s\n", buff);  
      
}
int main()
{
    read_file();
    return 0;
}

read.cpp是读一个文件,但是没有关闭文件描述符。如果一个进程打开的文件描述符达到最大值(一般是1024),将无法打开任何文件描述符,包括打开socket、管道、信号量、共享内存、消息队列。

检查结果:

8 检查类

// Student.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
using namespace std;

class Student {

public:
	Student() {
		cout << "Student = "<< sizeof(Student) << endl;

	}
	~Student() {

	}
    void Study() {
        cout << "I am studying "  << endl;
    }
	char name[20];
	int age;
    string address;

};
int main()
{
	cout << "Student : " << sizeof(Student) << endl;
	Student *p = new Student;
    p->Study();

    std::cout << "Hello World!\n";
}

终端输入命令:

cppcheck --enable=all Student.cpp

9 自动变量检查

对于自动变量,cppcheck可以查出变量未初始化、引用局部变量地址和返回局部变量的引用等问题。


#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;
void test(){
	int a;
	int b;
	int c = 0;
	c = a + b;
}
int f1(char **fp){
	char c = 'a';
	*fp = &c;
	return 0;
}
char *f2(int i){
	char c = 'a';
	return &c;
}
string &getstring(){
	string text = "abcd";
	return text;
}
int main()
{
    test();
	int *p = NULL;
	int a = 0;
	f1(&p);
	f2(a);
	string s = getstring();
    return 0;
}

检查结果:

10 cppcheck在TI C62项目上的实战应用

检查dod/src目录,输入命令:cppcheck src

检查结果:

发现一处越界,对比代码:

查看声明:

最终确认这是一处数组越界。

11 jenkins安装cppcheck插件

Cppcheck插件在构建工作区中扫描Cppcheck报告文件,并报告在静态C / C ++代码分析期间检测到的问题。

此插件提供以下功能:

  • 在构建,构建状态评估和图形之后配置要扫描的文件。
  • 趋势报告显示每种类型检测到的问题数。
  • 结果摘要和结果详细信息包括新问题和已解决的问题。
  • 列出突出问题的源代码。
  • 显示单个页面上突出显示的所有违规。
  • 仪表板视图 portlet显示每个作业的问题数。远程访问API(REST API)

12 Windows使用cppcheck

        12.1 选择分析-文件菜单,在弹出的对话框中选择文件,cppcheck给出检查结果。

可视化的界面更容易找到出错的位置。

        12.2 选择分析-目录菜单可以选择目录,例如选择dod/src

工具栏 可以过滤

        12.3 Cppcheck的误报

在C62上测试发现对于消息注册总是会误报。

13 总结

     Cppcheck是一款优秀的静态检查工具, 性能明显超出其它同类产品,如pclint、QAC等。Cppcheck能查出部分的内存泄漏、越界,有时候会漏报、误报,所以cppcheck的检查不能作为唯一的依据,也不能代替动态检查。Cppcheck与jenckins搭配使用,提交代码就可以对相关文件进行检查,避免将错误引入版本。

      Cppcheck对于提高代码质量的稳定性、可靠性是很有帮助的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值