1. 靜態分析工具 VS 編譯器
編譯器負責把C源程序快速、高效地轉變為可執行文件,不對代碼做類型檢查(特別是對分別編譯的程序),有益於做到快速與高效。
Lint沒有“高效”的要求,可以花更多時間對代碼進行更深入、仔細的檢查。
2. C代碼靜態分析工具
Its4 |
讀取一個或多個 C/C++源程序,將每個源程序分割成函數標志流,然后檢查生成的標志是否存在於漏洞數據庫中,從而得到每個源程序的所有錯誤警告列表,並帶有相關的描 述。其規則庫vulns.i4d定義了各種函數的危險等級,描述等,通過規則匹配來報出風險,但它不能理解程序上下文意思,存在很大的誤報。 |
Flawfinder |
詞法掃描和分析,內嵌了一些漏洞數據庫,如緩沖區溢出、格式化串漏洞等,掃描快,按照代碼中漏洞的風險等級對漏洞進行划分,可以快速找到存在的問題,誤報較高。 |
Rats |
掃描C、C++、Perl、PHP和Python開發的源程序中潛在的漏洞,掃描規則比較粗糙。 |
PC-lint |
一個由Gimpel Software提供的支持C/C++的商用程序 |
Splint |
(原來的 LCLint) 是一個GNU免費授權的 Lint程序,是一個動態檢查C語言程序安全弱點和編寫錯誤的程序。Splint會進行多種常規檢查,包括未使用的變量,類型不一致,使用未定義變量,無法執行的代碼,忽略返回值,執行路徑未返回,無限循環等錯誤。 |
3. splint安裝
./configure --prefix=$HOME/splint
make make install
4. 配置
splint提供了三種方式進行檢查的控制,分別是flags標志、 .splintrc配置文件和格式化注釋。
splint -showcol a.c //在檢測a.c時,告警消息中列數不被打印
splint -varuse a.c //在檢測a.c時,告警消息中未使用變量告警不被打印
格式化注釋:格式化注釋提供一個類型、變量或函數的額外的信息,可以控制標志設置,增加檢查效果。所有格式化注釋都以/*@開始,@*/結束,比如在函數參數前加 /*@null@*/,表示該參數可能是NULL,做檢測時,splint會加強對該參數的值的檢測。
-sysdirs /usr/include/:/usr/include/netinet/:/home/gaps/libevent/include/:/home/gaps/libsrc/hslib/common/:/home/gaps/libsrc/gaps/libsha/libincl:/home/gaps/libsrc/dci/include:/home/gaps/libsrc/hslib/libsxml:/home/gaps/src/mcmi/mcmi_cli:/home/gaps/libsrc/gaps/libgapssql:/home/gaps/libsrc/gaps/libgapssfs/libincl
+single-include
+skipsysheaders
+unixlib +bounds
-I/usr/include-I/home/gaps/incl
-I/home/gaps/libevent/include
-I/home/gaps/libincl
-I/home/gaps/libsrc/dci/include
-I/home/gaps/libsrc/gaps/libgapssfs/libincl
-I/home/gaps/libsrc/gaps/libgapssql
-I/home/gaps/libsrc/gaps/libsha/libincl -I/home/gaps/libsrc/hslib/common
-I/home/gaps/libsrc/hslib/libsxml -I/home/gaps/lua/include- I/home/gaps/sqlite/include
-I/home/gaps/src/mcmi/mcmi_cli -I/home/gaps/src/mcmi/memcachedSplint的unixlib比posixlib多了(如果用posixlib,自己寫的這幾個同名頭文件似乎就不會被splint include進去?checking macros階段看出來用上了?):
[1]<unistd.h>定義的socklen_t,in_addr_t,sa_family_t等類型
[2]<sys/select.h>定義的fd_set類型和select函數(遵循POSIX 1003.1-2001)。
[3]<pthread.h>定義的pthread_t,pthread_mutex_t等類型。但卻有pthread_create等函數聲明。
怎樣查看splint的posixlib庫包含了哪些頭文件?
Splint 知道的POSIX規格是IEEE 1003.1-1990,所以不支持之后規格(如IEEE Std 1003.1b-1993)導入的特性,如siginfo_t結構體等。有兩個辦法解決:[1]干凈的辦法是,更新posix.h后重新生成 posix.lcd和posixstric.lcd。Splint手冊第14.2節講述了這方面內容:splint 源碼包的lib目錄下就有 standard/posix/unix三個庫的頭文件和lcd文件。按照指示生成一個lcd文件后,在之后運行splint檢查時以“-load”選項加載一個自己創建的lcd(注意:最多只能加載一個自己創建的lcd)。[2]As a quick-and-dirty solution, you could provide a dummy definition for siginfo_t.
(4)自己工程定義的宏沒有設置好導致語法錯誤。
有些數據類型或函數是編譯器擴展的,例如上面的/usr/include/bits/sigthread.h的33行的__sigset_t應當用sigset_t代替:
sigemptyset((__sigset_t *)&sa.sa_mask);GCC編譯器內建的數據類型__built_va_list被GCC作為基本類型了。
所以,Splint手冊指出系統頭文件一般是不可解析的!要處理GCC所有內建的預處理宏、數據結構、函數很難,Splint郵件列表有人嘗試以這種方式lint linux內核模塊成功了。
可能自編C文件依賴於include的系統頭文件中某些擴展宏、數據結構、函數聲明,可以自己編寫與之同名的頭文件。這個很容易的:不需要修改工程中任何文件,並且一般寫兩三個很短的頭文件就行了。