Sparse

특징

  • Sparse는 MIT가 라이센스를 가지고 있는 코드 정적 분석 도구이다
    • 2003년 토발즈가 작성하기 시작
    • 2006년 부터 메인테이너로 Triplett가 관리
    • 2009년부터 Christopher Li가 관리
  • 설치 시 gcc 확장 형태로 내장 속성이 추가된다.
    • address_space: 섞여서 사용되는 포인터의 주소 공간 체크
    • noderef: dereferencing 금지 (*x로 포인터 전달 금지, &x는 가능)
    • context: 동기화(lock) 함수에서 사용
    • bitwise: integer 타입을 제한하여 타입 미스매치를 체크
    • 그 외 safe, force, nocast, 등
  • 다른 C 코드 정적 분석 도구
    • Smatch, Coccinelle, Splint, Uno, BLAST

설치

자동 설치

$ sudo apt-get install sparse

수동 설치

$ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
$ cd sparse
$ make
$ make install

~/.bashrc에 다음 내용을 추가한다.

export PATH=$PATH:$HOME/sparse/bin

사용법

  • C 옵션
    • make C=1
    • C=1 옵션은 모든 C 파일, C=2 옵션은 수정된 파일만 컴파일
  • 엔디안 체크 옵션
    • make C=2 CF=”-D__CHECK_ENDIAN__”

 

타입 체킹

enum 대신 사용할 수 있다.

        typedef int __bitwise pm_request_t;

        enum pm_request {
                PM_SUSPEND = (__force pm_request_t) 1,
                PM_RESUME = (__force pm_request_t) 2
        };

 

        typedef int __bitwise pm_request_t;

        #define PM_SUSPEND ((__force pm_request_t) 1)
        #define PM_RESUME ((__force pm_request_t) 2)

 

타입 선언이 서로 다른 것들을 찾아 경고한다.

void foo(__u64 hostbyte_value)
{
    /* __be64 bigendian_value = cpu_to_be64(hostbyte_value); */
    __be64 bigendian_value = hostbyte_value; /* INCORRECT */
    ...
}

 

타입 선언과 관련한 경고 메시지들

  • warning: restricted degrades to integer
  • warning: restricted degrades to integer
  • error: incompatible types for operation (-)
  • argument has type restricted unsigned short [usertype] a

 

락 체킹

  • __must_hold
    • 함수의 진출입 시 lock이 걸려있어야 한다. (진출입 시 체크)
  • __acquires
    • 함수를 빠져나갈 때에는 lock이 걸려있어야 한다. (진출 시 체크)
  • __releases
    • 함수에 진입하였을 때에는 lock이 걸려있어야 한다. (진입 시 체크)

 

__CHECKER__

리눅스에서 Sparse 기능을 사용할 수 있게 각 속성을 매크로로 정의하였다.

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

 

include/uapi/linux/types.h

/*
 * Below are truly Linux-specific types that should never collide with
 * any application/library that wants linux/types.h.
 */

#ifdef __CHECKER__
#define __bitwise__ __attribute__((bitwise))
#else
#define __bitwise__
#endif
#ifdef __CHECK_ENDIAN__
#define __bitwise __bitwise__
#else
#define __bitwise
#endif

typedef __u16 __bitwise __le16;
typedef __u16 __bitwise __be16;
typedef __u32 __bitwise __le32;
typedef __u32 __bitwise __be32;
typedef __u64 __bitwise __le64;
typedef __u64 __bitwise __be64;

typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;

 

참고

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.