sparse 是用于 C 语言的语法分析器,用以对 C 代码进行静态检查,它不但可以检查 ANSI C 而且还能检查具有 gcc 扩展的 C 。在 Linux 中,不但可以检查用户端代码,还可以检查内核代码。起初它由 Linus 编写,后来交给其他人维护。
获得一个新的sparse:
$ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
官方文档:
Documentation/dev-tools/sparse.rst
https://linux.die.net/man/1/sparse
LWN.net article: http://lwn.net/Articles/87538/
编译方法:
cd sparse; make; make install
由于kernel默认使用Sparse的@ top Makefile:
CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__
-Wbitwise -Wno-return-void $(CF)
所以在内核编译时,只要 make C=1/2 就可以了。
make C=1 会检查被编译的文件。
make C=2 会检查所有文件,不管是否被编译。
编译后,检查报告即可:
$ make -j4 C=2 > PORJECT_sparse_kernel_error.log 2>&1
$ cat ./PORJECT_sparse_kernel.log | grep “error:” | cut -d ‘:’ -f4- | sort | uniq -c | sort -g -r > PORJECT_sparse_kernel_error.log
PORJECT检测到的错误类型:
455 error: directive in argument list
42 error: incompatible types in comparison expression (different type sizes)
32 error: Expected ; at end of declaration
31 error: bad integer constant expression
19 error: cannot dereference this type
16 error: got +=
14 error: got buf
13 error: return with no return value
13 error: incompatible types in comparison expression (different signedness)
13 error: Expected ) in function declarator
12 error: cannot size expression
8 error: got -=
7 error: Trying to use reserved word 'break' as identifier
5 error: Trying to use reserved word 'case' as identifier
5 error: got }
5 error: Expected ; at the end of type declaration
4 error: return expression in void function
3 error: Trying to use reserved word 'return' as identifier
3 error: marked inline, but without a definition
3 error: incompatible types for operation (<)
2 error: Trying to use reserved word 'if' as identifier
2 error: too many errors
2 error: subtraction of different types can't work (different address spaces)
2 error: incompatible types for operation (!=)
2 error: incompatible types for operation (<=)
2 error: got 3
2 error: got 2
2 error: got ==
2 error: dubious one-bit signed bitfield
1 error: symbol 'panic' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/kernel.h:208) - different modifiers
1 error: symbol 'mtk_wcn_stp_psm_notify_stp' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/kernel/drivers/conn_soc/common/core/../core/include/stp_core.h:504) - incompatible argument 1 (different signedness)
1 error: symbol 'mt_get_chip_sw_ver' redeclared with different type (originally declared at /home/project/PORJECT/kernel/../mediatek/platform/mt6752/kernel/core/include//mach/mt_boot.h:58) - different signedness
1 error: symbol '__module_put_and_exit' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/module.h:449) - different modifiers
1 error: symbol 'lcm' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/lcm.h:6) - different modifiers
1 error: symbol 'kbase_pm_register_inuse_cores' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/gpu/mali/drivers/gpu/arm/midgard/mali_kbase_pm_policy.h:224) - different signedness
1 error: symbol 'gcd' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/gcd.h:6) - different modifiers
1 error: symbol 'g_call_state' redeclared with different type (originally declared at /home/project/PORJECT/kernel/../mediatek/kernel/include//mach/battery_common.h:185) - different signedness
1 error: symbol 'dprec_logger_trigger' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:145) - incompatible argument 1 (different signedness)
1 error: symbol 'dprec_logger_submit' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:155) - incompatible argument 1 (different signedness)
1 error: symbol 'dprec_logger_start' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:146) - incompatible argument 1 (different signedness)
1 error: symbol 'dprec_logger_done' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:147) - incompatible argument 1 (different signedness)
1 error: symbol 'do_exit' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/kernel.h:214) - different modifiers
1 error: symbol 'crc32_le' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/crc32.h:11) - different modifiers
1 error: symbol '__crc32c_le' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/crc32.h:14) - different modifiers
1 error: symbol 'crc32_be' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/crc32.h:12) - different modifiers
1 error: symbol 'complete_and_exit' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/kernel.h:216) - different modifiers
1 error: symbol '_bin2bcd' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/bcd.h:20) - different modifiers
1 error: symbol '_bcd2bin' redeclared with different type (originally declared at /home/project/PORJECT/kernel/include/linux/bcd.h:19) - different modifiers
1 error: incompatible types in comparison expression (different address spaces)
1 error: incompatible types for operation (==)
1 error: got 0
1 error: got \
1 error: Expected ) in function call
[分析]
455 error: directive in argument list //语法问题,non-issue.
32 error: Expected ; at end of declaration //使用了__restrict__,优化编译器的限定符引起的误报
19 error: incompatible types in comparison expression (different type sizes) //fixed
16 error: got += //使用了__restrict__,优化编译器的限定符引起的误报
14 error: got buf //使用了__restrict__,优化编译器的限定符引起的误报
13 error: return with no return value //有些是误报,没有明显逻辑错误,暂时不改
13 error: incompatible types in comparison expression (different signedness) //fixed
13 error: Expected ) in function declarator //使用了__restrict__,优化编译器的限定符引起的误报
8 error: got -= //使用了__restrict__,优化编译器的限定符引起的误报
7 error: Trying to use reserved word 'break' as identifier //使用了__restrict__,优化编译器的限定符引起的误报
5 error: Trying to use reserved word 'case' as identifier //使用了__restrict__,优化编译器的限定符引起的误报
5 error: got } //使用了__restrict__,优化编译器的限定符引起的误报
5 error: Expected ; at the end of type declaration //使用了__restrict__,优化编译器的限定符引起的误报
3 error: Trying to use reserved word 'return' as identifier //使用了__restrict__,优化编译器的限定符引起的误报
3 error: incompatible types for operation (<) //误报
2 error: Trying to use reserved word 'if' as identifier //使用了__restrict__,优化编译器的限定符引起的误报
2 error: subtraction of different types can't work (different address spaces) // 使用了__user限定符的指针page和指向page的的指针ptr作运算,误报说不同地址空间不能作运算
2 error: return expression in void function //void函数return 0, 不需要改
2 error: marked inline, but without a definition //focaltech_driver 驱动close api 声明inline 但实现没有inline,TP一般不会close,也没有逻辑性问题,暂时不改
2 error: incompatible types for operation (<=) //误报,void __iomem * p 使用__iomem时,告诉编译器忽略对变量的检查,但Smatch/Sparse不知道
2 error: got 3 //使用了__restrict__,优化编译器的限定符引起的误报
2 error: got 2 //使用了__restrict__,优化编译器的限定符引起的误报
2 error: got == //使用了__restrict__,优化编译器的限定符引起的误报
1 error: too many errors //使用了__restrict__,优化编译器的限定符引起的误报
1 error: symbol 'mtk_wcn_stp_psm_notify_stp' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/kernel/drivers/conn_soc/common/core/../core/include/stp_core.h:504) - incompatible argument 1 (different signedness) //声明使用UINT32 , 实现使用MTKSTP_PSM_ACTION_T enum,忽略
1 error: symbol 'mt_get_chip_sw_ver' redeclared with different type (originally declared at /home/project/PORJECT/kernel/../mediatek/platform/mt6752/kernel/core/include//mach/mt_boot.h:58) - different signedness //使用了__weak 限定符,误报
1 error: symbol 'kbase_pm_register_inuse_cores' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/gpu/mali/drivers/gpu/arm/midgard/mali_kbase_pm_policy.h:224) - different signedness //无逻辑错误,忽略
1 error: symbol 'g_call_state' redeclared with different type (originally declared at /home/project/PORJECT/kernel/../mediatek/kernel/include//mach/battery_common.h:185) - different signedness //无逻辑错误,忽略
1 error: symbol 'dprec_logger_trigger' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:145) - incompatible argument 1 (different signedness) //无逻辑错误,忽略
1 error: symbol 'dprec_logger_submit' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:155) - incompatible argument 1 (different signedness) //无逻辑错误,忽略
1 error: symbol 'dprec_logger_start' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:146) - incompatible argument 1 (different signedness) //无逻辑错误,忽略
1 error: symbol 'dprec_logger_done' redeclared with different type (originally declared at /home/project/PORJECT/kernel/mediatek/platform/mt6752/kernel/drivers/dispsys/display_recorder.h:147) - incompatible argument 1 (different signedness) //无逻辑错误,忽略
1 error: incompatible types in comparison expression (different address spaces) //误报
1 error: incompatible types for operation (!=) //非指针和NULL 比较,语法问题,暂时不改
1 error: incompatible types for operation (==) //extern vramsize; 没有指定类型,然后if(vramsize == 0), fixed
1 error: got 0 //使用了__restrict__,优化编译器的限定符引起的误报
1 error: got \ //使用了__restrict__,优化编译器的限定符引起的误报
1 error: Expected ) in function call //使用了__restrict__,优化编译器的限定符引起的误报
1 error: cannot size expression //使用了__restrict__,优化编译器的限定符引起的误报