靜態分析(static analysis)是指在不執行代碼的狀況下對其進行分析評估的過程,是軟件質量和軟件安全保障的重要一環。它經過詞法分析、語義分析、控制流分析、數據流分析等技術對代碼逐行解析暴露問題,從而協助咱們將許多在運行時纔會暴露的棘手麻煩扼殺於搖籃之中。php
代碼靜態分析可以識別諸多類型的漏洞或缺陷,輕至警告級的「變量未使用」,重至錯誤級的各種bug,這裏列舉幾種常見的、較嚴重的、可靜態檢測的問題。html
緩衝區溢出是指向緩衝區中存入超出其空間大小的數據量,致使多餘的數據覆蓋其餘區域的合法數據,相似倒入容器中的水過多而致使溢出,流到它不應去的地方,形成不可預期的後果。從實踐統計看,緩衝區溢出問題是軟件中最廣泛存在的漏洞問題,在C/C++這類不提供內存越界檢測的語言中尤甚。一般,發生緩衝區溢出的狀況有:python
strcpy
、_mbscpy
、strcat
、wcscat
、memcpy
、strncpy
、_mbsncpy
、strncat
、wcsncat
等)。// 字符串拷貝以前沒有對s作長度判斷,若是超過10,就會形成緩衝區溢出。 void func(char* s) { char buf[10]; strcpy(buf, s); }
printf
、fprintf
、sprintf
、swprintf
等)。// %n將前面打印的字串長度信息寫到相應地址 int len = 0; printf("This is a test string.%n", &len);
// 錯誤的寫法,此時長度信息會寫到地址爲0的內存空間中 int len = 0; printf("This is a test string.%n", len);
scanf
、fscanf
、sscanf
、gets
、getc
、fgets
、fgetc
等)。// 用戶輸入的字串長度不受控制,若是超過10,就會形成緩衝區溢出。 char buf[10]; scanf("%s", &buf);
內存泄漏通常指堆內存的泄漏(也有系統資源的泄漏),程序申請的內存資源沒有被合理地釋放,致使這部份內存不能被回收利用而形成資源的浪費。嚴重時,過多的內存泄漏會形成系統崩潰。C/C++語言沒有自動回收機制,須要程序員自行確保內存使用的閉環(new/delete
、alloc/free
、malloc/free
、GlobalAlloc/GlobalFree
成對使用)。git
一般,發生內存泄漏的狀況有:程序員
當指針變量未被初始化,或指向的內存已被回收時,該指針便成了野指針。其指向的內存地址是非法的,對這塊非法區域進行操做將致使不可預料的後果。github
// 對指針是否爲空的判斷看是嚴謹,實際上是無效的。 char *p = (char*)malloc(10); free(p); if (p != NULL) { strcpy(p, "danger"); }
根據工做須要,從可檢測的語言、使用平臺和受權三方面考量,調研了20餘種主流的C/C++代碼靜態分析工具。編程
工具 | 語言 | 平臺 | 受權 |
---|---|---|---|
AdLint | C | Windows, Linux, Mac OS, FreeBSD | 開源 |
Astrée | C | Windows, Linux | 付費 |
Bauhaus Toolkit | C, C++, Java, C#, Ada | Windows, Linux, Solaris | 付費 |
BLAST | C | Linux | 開源 |
Cppcheck | C, C++ | Windows, Linux | 開源 |
Coccinelle | C | Linux | 開源 |
Coverity | C, C++, C#, Java, JS, PHP, Python, Objective-C, Ruby, Swift, Fortran, VB | Windows, Linux, Mac OS, FreeBSD, Solaris | 付費 |
CppDepend | C, C++ | Windows, Linux | 付費 |
ECLAIR | C, C++ | Windows, Linux, Mac OS | 付費 |
Flawfinder | C, C++ | Python | 開源 |
Fluctuat | C, Ada | Windows, Linux, Mac OS, FreeBSD | 付費 |
Frama-C | C | Windows, Linux, Mac OS, FreeBSD | 開源/付費 |
CodeSonar | C, C++, Java, 二進制碼 | Windows, Linux, Mac OS, FreeBSD | 付費 |
Klocwork | C, C++, Java, C# | Windows, Linux, Solaris | 付費 |
LDRA Testbed | C, C++, Java, Ada | Windows, Linux, Mac OS | 付費 |
Parasoft C/C++test | C, C++ | Windows, Linux, Solaris | 付費 |
PC-Lint | C, C++ | Windows | 付費 |
Polyspace | C, C++, Ada | Windows, Linux, Mac OS | 付費 |
PRQA QA·Static Analyzers | C, C++, Java | Windows, Linux | 付費 |
SLAM | C | Windows | 免費 |
Sparse | C | Linux, Mac OS, BSD | 開源 |
Splint | C | Linux, FreeBSD, Solaris | 開源 |
TscanCode | C, C++, C#, Lua | Windows, Linux, Mac OS | 開源 |
根據如下標準,篩選出3款適用性較高的工具——Cppcheck、Flawfinder、TscanCode——進行詳細調研:windows
爲進行一次實踐對比,從TscanCode的GitHub上抓到一組現成的C/C++編碼問題示例,共94個CPP文件,考察三者的檢測效果。安全
運行平臺:Windows
被測語言:C/C++
測試集:TscanCode/samples/cppbash
Cppcheck可檢測的問題包括:
- Dead pointers
- Division by zero
- Integer overflows
- Invalid bit shift operands
- Invalid conversions
- Invalid usage of STL
- Memory management
- Null pointer dereferences
- Out of bounds checking
- Uninitialized variables
- Writing const data
並將問題分爲如下6類:
- 錯誤(error):bug。
- 警告(warning):預防性編程方面的建議。
- 風格警告(style):出於對代碼簡潔性的考慮(函數未使用、冗餘代碼等)。
- 可移植性警告(portability):64/32位可移植性、編譯器通用性等。
- 性能警告(performance):使代碼更高效的建議,但不保證必定有明顯效果。
- 信息消息(information):條件編譯方面的警告。
安裝十分簡便,只需在官網下載最新的可執行安裝包(本文目前爲cppcheck-1.83-x86-Setup.msi
)跟着嚮導「下一步」便可。
除了GUI,Cppcheck還支持與多種IDE(如VS、Eclipse、QtCreator等)、版本管理系統(如Tortoise SVN、Git)集成使用。
可對每次分析進行配置甚至自定義規則,並做爲項目文件進行保存或重載。
分析的結果報告可保存爲格式化純文本或XML,並可藉助Python pygments將XML生成爲HTML。
TscanCode是騰訊的開源項目,爲這次調研的惟一一款本土工具,起初構建於Cppcheck的基礎之上,後來進行了從新實現,並加入了對C#和Lua的支持。
TscanCode可檢測的問題包括:
- 空指針檢查,包含可疑的空指針,判空後解引用好比Crash等共3類subid檢查
- 數據越界,Sprintf_S越界共1類subid檢查
- 內存泄漏,分配和釋放不匹配同1類subid檢查
- 邏輯錯誤,重複的代碼分支,bool類型和INT進行比較,表達式永遠True或者false等共18類檢查
- 可疑代碼檢查,if判斷中含有可疑的=號,自由變量返回局部變量等共計15類檢查
- 運算錯誤,判斷無符號數小於0,對bool類型進行++自增等,共計11類檢查
並將問題分爲致命、嚴重、警告、提示、風格5類。
安裝一樣便捷,下載安裝包(本文目前爲TscanCodeV2.14.24.windows.exe
)跟着嚮導「下一步」便可。
TscanCode的提示信息能夠說直接照搬了Cppcheck,但給出的提示數量明顯少於Cppcheck,以mismatchsize.cpp
爲例:
void Demo() { //分配的內存空間不匹配 int i = malloc(3); }
Flawfinder由計算機安全專家David A. Wheeler我的開發,依託於Python,天然而然擁有了跨平臺性。
安裝:
pip install flawfinder
運行:
cd *python_path*/Scripts python flawfinder *directory_with_source_code*
實踐代表,Flawfinder對中文註釋更不友好,直接拿TscanCode的測試集跑會報編碼錯誤,儘管這些CPP文件原本就是Flawfinder文檔所建議的UTF-8格式:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 92: illegal multibyte sequence
將測試集批量轉換爲ANSI格式後方可正常運行:
David A. Wheeler本人也在官網特別聲明Flawfinder是款相對簡單的靜態分析工具,不進行數據流和控制流分析,甚至不識別函數的參數類型。
Flawfinder可將結果保存爲格式化純文本、HTML和CSV三種格式。
2018年4月10日~16日 無錫