splint

一、安装

1、在网络环境、配置OK的系统,可以 yum 一键安装

2、某些情况无法一键安装,需要下载源码自己安装

下载splint-3.1.2.tar.gz:https://github.com/splintchecker/splint

3、安装

[wishcell@localhost]~/test/splint-master% autoreconf -vif
[wishcell@localhost]~/test/splint-master% ./configure
[wishcell@localhost]~/test/splint-master% make
....
e.o lclsyntable.o lcltokentable.o sort.o symtable.o lclinit.o shift.o lclscan.o lsymbol.o mapping.o -lfl
/usr/bin/ld: 找不到 -lfl
collect2: 错误:ld 返回 1
make[3]: *** [splint] 错误 1
make[3]: 离开目录“/home/wishcell/test/splint-master/src”
make[2]: *** [all] 错误 2
make[2]: 离开目录“/home/wishcell/test/splint-master/src”
make[1]: *** [all-recursive] 错误 1
make[1]: 离开目录“/home/wishcell/test/splint-master”
make: *** [all] 错误 2
[wishcell@localhost]~/test/splint-master%
解决 -lfl 报错问题:
[root@localhost splint-master]# sudo yum install flex
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
正在解决依赖关系
--> 正在检查事务
---> 软件包 flex.x86_64.0.2.5.37-3.el7 将被 升级
---> 软件包 flex.x86_64.0.2.5.37-6.el7 将被 更新
--> 解决依赖关系完成
然后重新: ./configure && make 时间还挺长,最后仍然报错,还是找不到
原来需要安装开发包:
[root@localhost splint-master]# yum -y install flex-devel
再次 make ,很快完成
[root@localhost splint-master]# whereis splint
splint: /usr/local/bin/splint
[root@localhost splint-master]#

源代码安装

将 splint-3.1.2.tar.gz 直接解压
./configure && make
报错:
  cscanner.c:2133:yywrap not defined

解决办法:
   add function by myself:
int yywrap()
{
    return 1;
}

make && make install

但是自己实现了函数之后,虽然可以编译安装成功。
对实际检测结果却不知道有没有影响。

一个显而易见的错误竟然没有报出来
int main()
{
    char dest[4]
    char*src="this is a string“;
    memset(dest, 0, sizeof(dest));
    memcpy(dest,  src, strlen(src));
    return 0
}
用cppcheck一下字就发现了。
更让人崩溃的是 valgrind 竟然呀没能发现这个错误!!!!!

二、linux下面,超级严格的代码检查工具

1、基础用法,检验单个文件

A、示例代码

test.c:
int main()
{
    int a = 3;
    int b = 4;
    printf("a +b = %d", a +b);
    return 0;
}

B、用法

/usr/local/bin/splint test.c

2、检测工程,需要对复杂的目录结构下所有C文件检测

A、困难

此时,检测的每个C文件,都会要求包含其依赖的头文件。
即需要包含头文件。项目特别复杂,怎么办?

B、解决办法

可以信托项目中原来的 makefile 框架,在编译规则中,将生成
中间文件 .o 的操作,改为splint检测规则

C、举例

GTEST_DIR=./GTEST-1.7.0
CurrDir=$(shell pwd)
spline=/usr/bin/splint \
      -booltrue TRUE \
      -retvalint     \
      +bounds        \
      -type          \
      +boundsread    \
      +trytorecover  \
      -nullstate     \
      charindex      \
      -immediatetrans\
      -mustfreefresh \
      -nullret       \
      mustfreeonly   \
      -temptrans     \
      -dependenttrans\
      -boundswrite   \
      -bufferoverflowhigh \
      -retvalother   \
      -mayaliasunique\
      -exportlocal   \
      -initalelements\
      +ignoresigns   \
      +ignorequals   \
      +relaxtypes    \
      -predboolothres\
      -predboolint   \
      -globstate     \
      -unqualifiedtrans\
      -compdestroy   \
      -compdef       \
      -usedef        \
      -paramuse      \
      -nullassign    \
      -formattype    \
      -onlytrans     \
      -nullpass      \
      -usereleased   \
      -redef         \
      -compmempass   \
      -branchstate   \
      +posixlib      \
      -shiftnegative \
      -boolops       \
      -evalorder     \
      -unregcog      \
      -likelybool

PrjDir = ../
Module1= ../module_1/source
Module2= ../module_2/source
Module3= ../module_3/source

CaseDir = ./case
stubDir = ./stub/source

linux_env=$(shell getconf LONG_BIT)
ifeq($(linux_env), 32)
   DEFS=-DMACHINE_BIT32=32
else
   DEFS=-DMACHINE_BIT64=64
endif

INCS=-I../module_1/include \
     -I../module_2/include \
     -I../module_3/include \
     -I$(GTEST_DIR)/include\
     -I$(GTEST_DIR)/include/gtest \
     -I$(GTEST_DIR)/include/gtest/internal

vpath %c $(../module_1)
vpath %c $(../module_2)
vpath %c $(../module_3)

PrjSrc=$(notdir $(wildcard $(module1_dir)/*.c))\
       $(notdir $(wildcard $(module2_dir)/*.c))\
       $(notdir $(wildcard $(module3_dir)/*.c))
PrjOBJ=$(PrjSrc:%.c=$(PrjOBJDir%.x))
stubOBJ=$(stubSrc:%.c=$(StubOBJDir%.x))

#这里原来是做中间文件生成的,但是现在让它生成检测日志
$(PrjOBJDir)%.x : %.c
    @$(SPLINT) ${INCS} $< || echo ''

$(TESTS): ${PrjObj} ${CaseObj} ${StubObj}
    echo ''

.PHONY: clean
clean:
    rm -f $(TESTS) *o *.gcda *

三、强大的测试能力

1、典型示例

A、典型案例背景说明

对数据非法越界操作,连valgrind都无法检测,甚至一个warning都没有.
在splint的检测报告中,显然看到了对它的告警

B、示例代码

混用结构体中的 char data[0]; 和 char *data 成员。
造成特定类型cpu环境崩溃。在某些环境上,无异常症状

C、实例检测效果

i、先用 valgrind 做对比实验

valgrind --tool=memcheck -leak-check=full --max-stackframe=20000000 ./xx > log 2>&1

ii、splint 检测结果

在修改 splint 告警的过程中,必然会解决掉越界问题

发表评论