Contenu connexe Similaire à cppcheck源码分析 (20) cppcheck源码分析1. Cppcheck 架构分析
自动变量检查:
Cppcheck 概述
返回自动变量(局部变量)指针
越界检查:
静态代码分析工具
数组越界
类检查:
构造函数,初始化
检查点
内存泄露检查:
空指针检查:
废弃函数检查
其他:
4. 参数分析
外部输入
class Settings
{
内部抽象 class Settings
…
std::string _append;
std::string userDefines;
std::list<std::string> _includePaths;
std::list<Rule> rules;
…
}
字符交互模式
CmdLineParser parser(&_settings);
7. Tokenize
符号:+-*/;…等
变量名
函数名
解析代码成符号
由 class Tokenizer实现
实现接口 class Tokenizer::tokenize()
8. Simplify
目的:
简化复杂代码
统一化
由 class Tokenizer实现
实现接口 class Tokenizer::simplifyTokenList()
Simplify规则
对变量
对条件循环语句if 、for、while
(详细规则见word)
9. Cppcheck 核心类class cppcheck
Cppcheck程序的主干类
核心函数check()
处理入口,在此函数对输入代码进行初步分析处理,最后将代码传
递给 CheckFile().
核心函数CheckFile()
函数功能是分析一个代码文件, CheckFile()会将代码流做
进一步的分析,做tokenize,simplify ,处理后分析代码,报告
错误
12. 检查类的组织方式:
static std::list<Check *> _instances;
// Register this check class (by creating a
static instance of it)
namespace std::list<Check *> &instances()
static
{ {
链表在哪?
static std::list<Check *> _instances;
CheckOther instance;
}
check类instances()函数中静态变量
return _instances;
InlineCheck::Check(const std::string &aname)
}
: _name(aname), _tokenizer(0),
_settings(0), _errorLogger(0)
:{
怎样加入检查类链表?
instances().push_back(this);
instances().sort(std::less<Check *>());
} 父类的构造函数执行时加入检查链表
13. Class check
protected:
const std::string _name;
const Tokenizer * const _tokenizer;
const Settings * const _settings;
ErrorLogger * const _errorLogger;
Cppcheck核心类check
virtual void runChecks(****){ }
check子类都会实现
//不是所有
virtual void runSimplifiedChecks(***) = 0; //所有check子类都会实
现
void reportError() //报
告误差,所有check子类都会用到
virtual void getErrorMessages(****) = 0; //所有check子类都会实现,
最终都会调用reportError()
Void runChecks()
主要是检查经过tokenize,但未经过simplify的代码流
Void runSimplifiedChecks()
主要是检查经过tokenize,但未经过simplify的代码流
14. 用户扩展接口
CheckOther : public Check
Cppcheck 用户扩展类
……
CheckOther
virtual void runChecks(****){ }
virtual void runSimplifiedChecks(***) = 0; //实现
//实现
添加检查函数方法:
17. 自动变量检查
自动变量问题
自动变量也就是局部变量,存储空间
在栈stack中,函数结束时空间被释放,如果此时变
量地址被外部空间的函数使用,将会引起错误。
自动变量暴露到外部窗口
从参数(指向地址变量指针即指向指针的指针)
return
全局指针变量…
其他 ….
18. 错误举例:
由参数传递局部变量地址 由程序返回
int f(char ** fp) char* f(int i)
{ {
Char c=’a’; char c=‘a’;
*fp=&c;
return 0; return &c;
自动变量检查
} }
(error) Assigning address of (error) Return of the address
local auto-variable to a of an auto-variable
function parameter.
24. std::string & f()
{
std::string str_local;
返回引用函数的问题
return str_local;
}
当f()运行结束时 str_local其实已经被释放了。
*好消息是 gcc就能查出此类问题
27. .returncstr()
描述:检查返回字符串自动地址的函数
(error) Returning pointer to auto variable
关键数据 std::set<unsigned int> localvar;
存储所有发现的自动变量
寻找目标函数——返回字符串的函数
特征 "const char *" 或 "> & %var% ("
30. 缓冲区溢出检查
缓冲区溢出问题
缓冲区也就是一块内存空间,它可以是在
栈中的局部变量(例如,静态数组),也可以是堆中的
内存区域,程序中动态产生(例如,malloc,C++支持的
动态数组)变量也就是局部变量。
所谓溢出也就是访问的地址空间超出了缓
冲区内存区域,常见有两种方式导致溢出,一是显示的
index越界,如数组越界,另外就是一些内存操作函数使
用不当引发,如memcpy,memset…等内存操作函数
31. 错误举例:
由index越界 内存操作程序使用不当
void f() void f()
{ {
char arrary[10]; char* buffer=new
char c; char[10];
c= arrary[11]; memset(buffer,0,11);
缓冲区溢出检查
} }
33. 缺陷
不支持指针传递
识别缓冲区精确度不高
动态数组,malloc固定空间等缓冲区不能识别
字符串常量 char* p=“hello”
(注:这段空间不是缓冲区,不可写哦)
内存操作函数检查的覆盖面不光,及一些双内存空间操作检查的不好
如memcpy(void *destin, void *source, unsigned n);
34. 类检查
面向对象编程问题
c++的面向对象编程存在一些安全隐患,
一 些经 典 的c++编程 书 籍都 有 提到 ,cppcheck实 现了
《effective c++》中提到的一些安全隐患检查
如:多态基类需要实现vitual的析构函数
不在构造和析构函数中使用vitual函数
operator = 必须返回*this
operator = 需处理自我赋值的情况
……
这些特性要加 –s 才启动
39. 内存泄露检查
内存泄露问题
内存泄露指的是在程序运行时,动态的
申请了内存(堆),但是使用过后没有释放,导致一些
内存永远得不到收回。
这是cppcheck最有价值的检查功能,也是
实现代码最长的一块检查
42. Struct base
{
char *p;
}
Void f()
典型错误类型
{
struct base *q;
q=malloc(sizeof(struct base ))
q->p=malloc(12);
free(q);
}
43. Class CheckMemoryLeakStructMember
void runSimplifiedChecks(…)
实现接口(runSimplifiedChecks)
{
CheckMemoryLeakStructMember checkMemoryLeak( …);
checkMemoryLeak.check();
}
核心函数
check()
辅助函数
getAllocType() getDeallocat ionType()
45. class base{
private:
int i;
char *p;
char *q;
public :
int j;
base();
~base();
典型错误类型
void memalloc();
void memdealloc();
}
base::base(){
p= malloc(12);
}
void base::memalloc(){
q = malloc(12);
free(p);
}
47. Class CheckMemoryLeakInClass
void runSimplifiedChecks(…)
实现接口(runSimplifiedChecks)
{
…
checkMemoryLeak.check();
}
核心函数
check() , variable()
辅助函数
getAllocType() getDeallocationType()
50. Class CheckMemoryLeakNoVar
void runSimplifiedChecks(…)
实现接口(runSimplifiedChecks)
{
CheckMemoryLeakNoVar checkMemoryLeak( …);
checkMemoryLeak.check();
}
核心函数
check()
辅助函数
getAllocType() getDeallocat ionType()