커널 코드를 보다 보니 이상한 문법의 코드가 있어서 확인해보았다.
203 static int expand_fdtable(struct files_struct *files, int nr)
204 __releases(files->file_lock)
205 __acquires(files->file_lock)
206 {
expand_fdtable() 함수를 보면, 파라미터 정의 다음 줄에 __releases / __acquires 라는 함수 비슷한 것이 정의되어있다. 이를 찾아보면 include/linux/compiler.h 파일에 다음과 같이 정의되어 있다.
6 #ifdef __CHECKER__
7 # define __user __attribute__((noderef, address_space(1)))
8 # define __kernel __attribute__((address_space(0)))
9 # define __safe __attribute__((safe))
10 # define __force __attribute__((force))
11 # define __nocast __attribute__((nocast))
12 # define __iomem __attribute__((noderef, address_space(2)))
13 # define __acquires(x) __attribute__((context(x,0,1)))
14 # define __releases(x) __attribute__((context(x,1,0)))
15 # define __acquire(x) __context__(x,1)
16 # define __release(x) __context__(x,-1)
17 # define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
18 # define __percpu __attribute__((noderef, address_space(3)))
19 #ifdef CONFIG_SPARSE_RCU_POINTER
20 # define __rcu __attribute__((noderef, address_space(4)))
21 #else
22 # define __rcu
23 #endif
24 extern void __chk_user_ptr(const volatile void __user *);
25 extern void __chk_io_ptr(const volatile void __iomem *);
26 #else
27 # define __user
28 # define __kernel
29 # define __safe
30 # define __force
31 # define __nocast
32 # define __iomem
33 # define __chk_user_ptr(x) (void)0
34 # define __chk_io_ptr(x) (void)0
35 # define __builtin_warning(x, y...) (1)
36 # define __acquires(x)
37 # define __releases(x)
38 # define __acquire(x) (void)0
39 # define __release(x) (void)0
40 # define __cond_lock(x,c) (c)
41 # define __percpu
42 # define __rcu
43 #endif
__CHEKCER__ 가 정의되어 있는 경우에 추가되는데, 이 것은 gcc 를 위한 것이 아니고, Sparse 라는 툴을 위한 코드이다.
Sparse 에 의해서 수행되는 check 중 일부는 __attribute__ 를 사용하거나, Sparse 고유 specifier 인 __context__ 를 사용한다. Sparse 는 아래와 같은 attribute 를 정의한다.
- address_space(num)
- bitwise
- fore
- context(expression, in_context, out_context)
위 정의를 잘 보면 익숙한 키워드가 보인다. __user / __kernel 이 그것이다. 2.6.7 부터 커널 코드에서 사용되기 시작한 지시어로 해당 변수가 속한 위치를 나타내 준다. __user 는 일반적인 커널 컴파일시에는 empty string 으로 빌드되지만, sparse 를 사용하는 경우 해당 포인터는 분리된 address space 가 되고 이 영역이 dereference 가 되지 않도록 한다.
Sparse 는 이를 기준으로 user 와 kernel 포인터를 섞어서 사용하는 경우, user 영역에 직접 접근하는 경우를 찾아낸다. 그 외에도 상수값의 최대치를 넘어서는 경우, 내장 어셈블리 코드의 실수, switch 문의 잘못된 사용등 다양한 조건 체크를 수행한다.⑵
Sparse 가 설치되어 있다면, make 시에 C=1 옵션을 추가해서 컴파일하면 된다. 외부 모듈도 같은 방식으로 체크할 수 있다.
Sparse 를 찾아보면, 위키피디아에서 잘 정의되어 있다. 상세한 내용은 아래 링크를 참조한다.
< Reference >
1) : http://en.wikipedia.org/wiki/Sparse
2) : http://lwn.net/Articles/87538/
'IT 기술 > 리눅스 커널' 카테고리의 다른 글
[C] _Generic keyword (0) | 2021.08.26 |
---|---|
[linux] find_first_zero_bit() 분석 (0) | 2013.05.14 |
커널 로컬 버전 세팅 (0) | 2012.11.09 |
Linux kernel CPU Frequency 변경(DVFS) 코드 (2) | 2011.02.11 |
kjournald 에 IPPRIO_CLASS_RT 권한 부여 (0) | 2010.05.03 |