linux kernel - sparse 靜態分析工具
這是 linus Torvalds 從 2003 年開始的專案,
像商用軟體 Coverity 的 SWAT, 也是做靜態分析, 但 Sparse 不用錢^^
sparse 是一個靜態代碼分析工具, 可以檢查所寫的代碼是否有些問題.
他是透過 gcc 的擴展屬性 __attribute__, 以及自己定義的 __context__,
來對代碼進行靜態檢查.
安裝方式:
1. 得到最新的 source code 來編譯安裝
$ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
$ make
$ sudo cp sparse /usr/bin/sparse
2. make C=2
我們寫一個簡單的 spin lock 來看看.
https://github.com/neojou/new_ldd/blob/master/sparse-lock/sparse-lock.c
做了 spin_lock 但不做 spin_unlock
warning: context imbalance in 'work_handler1' - different lock contexts for basic block
做了 spin_unlock 但不做 spin_lock
warning: context imbalance in 'work_handler1' : unexpected unlock
--
acquire 作法:
# define __acquire(x) __context__(x,1)
--
接下來我們把 rtw88-usb 也加上 sparse check 並修改.
中間遇到 __le32 / __le16 的 bitwise 檢查. patch 如下:
https://github.com/neojou/rtw88-usb/commit/3f10af10ae5909bea41c931378e1cd89627078a4
在這個
https://lore.kernel.org/patchwork/patch/863311/
中提議的 le32_get_bits() 和 le32p_replace_bits()
是在 include/linux/bitfield.h, 這邊利用 compiler 的寫法和 C define 用法值得參考
#define ____MAKE_OP(type,base,to,from) \ static __always_inline __##type type##_encode_bits(base v, base field) \ { \ if (__builtin_constant_p(v) && (v & ~field_mask(field))) \ __field_overflow(); \ return to((v & field_mask(field)) * field_multiplier(field)); \ } \ static __always_inline __##type type##_replace_bits(__##type old, \ base val, base field) \ { \ return (old & ~to(field)) | type##_encode_bits(val, field); \ } \ static __always_inline void type##p_replace_bits(__##type *p, \ base val, base field) \ { \ *p = (*p & ~to(field)) | type##_encode_bits(val, field); \ } \ static __always_inline base type##_get_bits(__##type v, base field) \ { \ return (from(v) & field)/field_multiplier(field); \ } #define __MAKE_OP(size) \ ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ ____MAKE_OP(u##size,u##size,,) ____MAKE_OP(u8,u8,,) __MAKE_OP(16) __MAKE_OP(32) __MAKE_OP(64)其他還有如下, 後續有空時繼續研究:
宏名稱
|
宏定義
|
檢查點
|
__bitwise | __attribute__((bitwise)) | 確保變量是相同的位方式(比如 bit-endian, little-endiandeng) |
__user | __attribute__((noderef, address_space(1))) | 指針地址必須在用戶地址空間 |
__kernel | __attribute__((noderef, address_space(0))) | 指針地址必須在內核地址空間 |
__iomem | __attribute__((noderef, address_space(2))) | 指針地址必須在設備地址空間 |
__safe | __attribute__((safe)) | 變量可以為空 |
__force | __attribute__((force)) | 變量可以進行強制轉換 |
__nocast | __attribute__((nocast)) | 參數類型與實際參數類型必須一致 |
__acquires(x) | __attribute__((context(x, 0, 1))) | 參數x 在執行前引用計數必須是0,執行後,引用計數必須為1 |
__releases(x) | __attribute__((context(x, 1, 0))) | 與 __acquires(x) 相反 |
__acquire(x) | __context__(x, 1) | 參數x 的引用計數 + 1 |
__release(x) | __context__(x, -1) | 與 __acquire(x) 相反 |
__cond_lock(x,c) | ((c) ? ({ __acquire(x); 1; }) : 0) | 參數c 不為0時,引用計數 + 1, 並返回1 |
留言
張貼留言