Linux开发工具-sparse
简介
sparse是Linux内核开发者早期开发的静态代码检查工具,用于在编译阶段快速发现代码中隐含的问题,像加解锁未配对等。
sparse利用了GCC专门提供的编译attribute来实现。
安装
- 方式1 源码编码
- git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
- cd sparse
- make
- make install
- 方式2 安装包
- apt install sparse
使用说明
-
命令:sparse xxx.c
注意: sparse本身有点编译器性质, 它在预处理源文件时会自动打开功能宏__CHECKER__
-
Linux kernel
-
Makefile
# Call a source code checker (by default, "sparse") as part of the # C compilation. # # Use 'make C=1' to enable checking of only re-compiled files. # Use 'make C=2' to enable checking of *all* source files, regardless # of whether they are re-compiled or not. # # See the file "Documentation/sparse.txt" for more details, including # where to get the "sparse" utility. ifeq ("$(origin C)", "command line") KBUILD_CHECKSRC = $(C) endif ifndef KBUILD_CHECKSRC KBUILD_CHECKSRC = 0 endif CHECK = sparse CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise -Wno-return-void $(CF) export KBUILD_CHECKSRC
-
scripts/Makefile.build
# Linus' kernel sanity checking tool ifneq ($(KBUILD_CHECKSRC),0) ifeq ($(KBUILD_CHECKSRC),2) quiet_cmd_force_checksrc = CHECK $< cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; else quiet_cmd_checksrc = CHECK $< cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; endif endif define rule_cc_o_c $(call echo-cmd,checksrc) $(cmd_checksrc) \ $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ $(cmd_modversions_c) \ $(call echo-cmd,record_mcount) \ $(cmd_record_mcount) \ scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \ $(dot-target).tmp; \ rm -f $(depfile); \ mv -f $(dot-target).tmp $(dot-target).cmd endef
-
include/linux/compiler.h
#ifdef __CHECKER__ # define __user __attribute__((noderef, address_space(1))) # define __kernel __attribute__((address_space(0))) # define __safe __attribute__((safe)) # define __force __attribute__((force)) # define __nocast __attribute__((nocast)) # define __iomem __attribute__((noderef, address_space(2))) # define __must_hold(x) __attribute__((context(x,1,1))) # define __acquires(x) __attribute__((context(x,0,1))) # define __releases(x) __attribute__((context(x,1,0))) # define __acquire(x) __context__(x,1) # define __release(x) __context__(x,-1) # define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) # define __percpu __attribute__((noderef, address_space(3))) #ifdef CONFIG_SPARSE_RCU_POINTER # define __rcu __attribute__((noderef, address_space(4))) #else # define __rcu #endif extern void __chk_user_ptr(const volatile void __user *); extern void __chk_io_ptr(const volatile void __iomem *); #else # define __user # define __kernel # define __safe # define __force # define __nocast # define __iomem # define __chk_user_ptr(x) (void)0 # define __chk_io_ptr(x) (void)0 # define __builtin_warning(x, y...) (1) # define __must_hold(x) # define __acquires(x) # define __releases(x) # define __acquire(x) (void)0 # define __release(x) (void)0 # define __cond_lock(x,c) (c) # define __percpu # define __rcu #endif
-
make C=1:检查重新编译的C文件
-
make C=2:检查所有的C文件(不论是否有重新编译)
-
-
普通程序
-
示例程序
#include <stdio.h> typedef int lock_t; #ifdef __CHECKER__ # define __must_hold(x) __attribute__((context(x,1,1))) # define __acquires(x) __attribute__((context(x,0,1))) # define __releases(x) __attribute__((context(x,1,0))) # define __acquire(x) __context__(x,1) # define __release(x) __context__(x,-1) #else # define __must_hold(x) # define __acquires(x) # define __releases(x) # define __acquire(x) (void)0 # define __release(x) (void)0 #endif static inline void lock_t_lock(lock_t *ll) __acquires(ll); static inline void lock_t_unlock(lock_t *ll) __releases(ll); static inline void lock_t_lock(lock_t *ll) { __acquire(ll); } static inline void lock_t_unlock(lock_t *ll) { __release(ll); } static lock_t mylock; void run(int a) { lock_t_lock(&mylock); if (a == 0) { return; } lock_t_unlock(&mylock); } int main(int argc, char *argv[]) { run(1); return 0; }
-
运行效果
root@ubuntu:~# gcc test.c root@ubuntu:~# root@ubuntu:~# root@ubuntu:~# sparse test.c test.c:35:6: warning: symbol 'run' was not declared. Should it be static? test.c:35:6: warning: context imbalance in 'run' - wrong count at exit
-
网友评论