Linux开发工具-sparse

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 
      
      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
      

你可能感兴趣的:(Linux开发工具-sparse)