1. 静态分析工具 VS 编译器
编译器负责把C源程序快速、高效地转变为可执行文件,不对代码做类型检查(特别是对分别编译的程序),有益于做到快速与高效。
Lint没有“高效”的要求,可以花更多时间对代码进行更深入、仔细的检查。
2. C代码静态分析工具
Its4 |
读取一个或多个 C/C++源程序,将每个源程序分割成函数标志流,然后检查生成的标志是否存在于漏洞数据库中,从而得到每个源程序的所有错误警告列表,并带有相关的描 述。其规则库vulns.i4d定义了各种函数的危险等级,描述等,通过规则匹配来报出风险,但它不能理解程序上下文意思,存在很大的误报。 |
Flawfinder |
词法扫描和分析,内嵌了一些漏洞数据库,如缓冲区溢出、格式化串漏洞等,扫描快,按照代码中漏洞的风险等级对漏洞进行划分,可以快速找到存在的问题,误报较高。 |
Rats |
扫描C、C++、Perl、PHP和Python开发的源程序中潜在的漏洞,扫描规则比较粗糙。 |
PC-lint |
一个由Gimpel Software提供的支持C/C++的商用程序 |
Splint |
(原来的 LCLint) 是一个GNU免费授权的 Lint程序,是一个动态检查C语言程序安全弱点和编写错误的程序。Splint会进行多种常规检查,包括未使用的变量,类型不一致,使用未定义变量,无法执行的代码,忽略返回值,执行路径未返回,无限循环等错误。 |
3. splint安装
./configure --prefix=$HOME/splint
make make install
4. 配置
splint提供了三种方式进行检查的控制,分别是flags标志、 .splintrc配置文件和格式化注释。
splint -showcol a.c //在检测a.c时,告警消息中列数不被打印
splint -varuse a.c //在检测a.c时,告警消息中未使用变量告警不被打印
格式化注释:格式化注释提供一个类型、变量或函数的额外的信息,可以控制标志设置,增加检查效果。所有格式化注释都以/*@开始,@*/结束,比如在函数参数前加 /*@null@*/,表示该参数可能是NULL,做检测时,splint会加强对该参数的值的检测。
-sysdirs /usr/include/:/usr/include/netinet/:/home/gaps/libevent/include/:/home/gaps/libsrc/hslib/common/:/home/gaps/libsrc/gaps/libsha/libincl:/home/gaps/libsrc/dci/include:/home/gaps/libsrc/hslib/libsxml:/home/gaps/src/mcmi/mcmi_cli:/home/gaps/libsrc/gaps/libgapssql:/home/gaps/libsrc/gaps/libgapssfs/libincl
+single-include
+skipsysheaders
+unixlib +bounds
-I/usr/include-I/home/gaps/incl
-I/home/gaps/libevent/include
-I/home/gaps/libincl
-I/home/gaps/libsrc/dci/include
-I/home/gaps/libsrc/gaps/libgapssfs/libincl
-I/home/gaps/libsrc/gaps/libgapssql
-I/home/gaps/libsrc/gaps/libsha/libincl -I/home/gaps/libsrc/hslib/common
-I/home/gaps/libsrc/hslib/libsxml -I/home/gaps/lua/include- I/home/gaps/sqlite/include
-I/home/gaps/src/mcmi/mcmi_cli -I/home/gaps/src/mcmi/memcached有些数据类型或函数是编译器扩展的,例如上面的/usr/include/bits/sigthread.h的33行的__sigset_t应当用sigset_t代替:
sigemptyset((__sigset_t *)&sa.sa_mask);GCC编译器内建的数据类型__built_va_list被GCC作为基本类型了。
所以,Splint手册指出系统头文件一般是不可解析的!要处理GCC所有内建的预处理宏、数据结构、函数很难,Splint邮件列表有人尝试以这种方式lint linux内核模块成功了。
可能自编C文件依赖于include的系统头文件中某些扩展宏、数据结构、函数声明,可以自己编写与之同名的头文件。这个很容易的:不需要修改工程中任何文件,并且一般写两三个很短的头文件就行了。