특징
- 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__”
Sparse 체킹 기능들
타입 체킹
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이 걸려있어야 한다. (진입 시 체크)
주소 공간 체킹
address_space()
다음 항목들은 사용자가 지정한 주소에 대해 gcc 컴파일러로 하여금 사용자의 코드가 적절한 주소 공간을 사용하는 변수를 사용했는지 체크하도록 한다.
- __user
- 유저 주소
- __kernel
- 커널 주소
- __iomem
- io 주소
- __percpu
- percpu 주소
- __rcu
- rcu 주소
다음과 같이 __percpu를 사용한 예를 보여준다.
int *p; DEFINE_PER_CPU(int , a); p = this_cpu_ptr(&a); <--- (O) p = &a; <--- (X) Sparce 정적 툴을 사용하여 컴파일 시 에러 출력
주의: int 타입의 per-cpu 변수 a에 대한 실제 주소는 &a – <cpu별 offset>이 사용되는 주소이므로 일반 적인 포인터 변수와 같이 사용될 수 없다.
__CHECKER__
sparse 정적 툴 사용 시 __CHECKER__가 define되어 동작한다. 다음 코드는 리눅스에서 Sparse 기능을 사용할 때 사용하는 속성들을 매크로로 정의하였다.
include/linux/compiler_types.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))) # define __rcu __attribute__((noderef, address_space(4))) # define __private __attribute__((noderef)) extern void __chk_user_ptr(const volatile void __user *); extern void __chk_io_ptr(const volatile void __iomem *); # define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member)) #else /* __CHECKER__ */ # ifdef STRUCTLEAK_PLUGIN # define __user __attribute__((user)) # else # define __user # endif # 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 # define __private # define ACCESS_PRIVATE(p, member) ((p)->member) #endif /* __CHECKER__ */
__bitwise__
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 #define __bitwise __bitwise__
참고
- Sparse | kernelnewbies.org
- sparse(1) – Linux man page | die.net
- Sparse (Linus Torvalds; Al Viro) | Yarchive
- Finding kernel problems automatically | LWN.net