代碼靜態檢查工具PC-Lint運用實踐
如何提交zero bug的產品,如何盡早發現bug,是軟件開發工程師和測試工程師都需要思考的問題。我認為高質量的代碼是關鍵,具體實施保障辦法有:框架約束,代碼評審,以及測試用例的設計和執行。
l 框架約束,可以將程序員從編寫沒有營養、易出錯的代碼工作中解放出來。程序員只需要寫一些配置或描述,就可以由框架生成可運行的代碼框架。這既提高了程序員的工作效率,使程序員關注在業務邏輯實現上,也由於框架的約束使程序形成了統一的風格和代碼結構。同時由於是自動生成的框架代碼,這部分經過嚴格的測試,可以確保是高質量的代碼,大大降低Bug數。
l 代碼評審,可以發現一些表面問題,如缺乏注釋、大量使用全局變量以及明顯的一些可能引發Bug的問題(如在不知道字符串長度的情況下使用Copy等),這其中包括程序員編碼的基本素質和編程風格兩個因素。良好的編程風格,可以從根本上減少bug隱患,也可以減少代碼維護成本。
l 測試用例的設計和執行,可以發現一些代碼邏輯上的問題,也是一道檢驗程序健壯性的保護屏。
在實際項目執行階段,可能會沒有框架約束,而且開發團隊的工作任務繁忙,前期階段他們根本沒有太多的時間去進行代碼評審。那么如何保證代碼的高質量呢?我們測試團隊研究並使用了一種代碼靜態分析工具PC-Lint,它類似於自動化地源代碼評審,使得在項目前期階段,測試人員除了寫測試用例外,還可以盡早地發現程序中的bug,為開發人員提供修改意見。
PC-Lint是Gimpel Software公司開發的一個C/C++代碼靜態檢查工具。它支持幾乎所有流行的編輯環境和編譯器,比如Borland C++從1.x到5.x各個版本、Borland C++ Build、GCC、VC,VC.net、Source insight等等,也支持16/32/64位的平台環境。它主要由以下文件組成:
- Lint-nt.exe Windows下的執行文件
- msg.txt 全部選項幫助說明文件
- PC-Lint.pdf 幫助文件
- config.exe 配置程序
- std.lnt 標准配置文件
- options.lnt 選項配置文件
- .\Lnt子目錄下的各種開發編譯環境的配置文件
由於它有可執行文件Lint-nt.exe,所以我們可以將它整合到編輯環境中,例如VC6。VC6環境下PC-lint的命令參數示例-u -iC:\lint std.lnt $(FileName)。Source insight環境下PC-lint的命令參數示例d:\lint\lint-nt.exe -u -iC:\lint std.lnt env-si %f, 如果需要Lint當前打開文件的同一目錄下所有文件,可以將%f改成%d\*.cpp。
其中,std.lnt文件中可以包含其他配置文件,還可以包含各種配置選項,有點類似C的頭文件,里面可以include許多其他頭文件,不過PC-Lint配置文件包含其他配置文件不需要寫include,直接寫文件名就可以了。std.lnt內容示例如下:
// Microsoft C and Visual C++ 6.x, -si4 -sp4, lib-stl.lnt lib-w32.lnt
// Standard lint options
au-ds.lnt
co-msc60.lnt //PC-Lint提供的對VC6的告警屏蔽文件
lib-stl.lnt lib-w32.lnt //PC-Lint提供的對stl和VC6庫頭文件的告警屏蔽文件
options.lnt -si4 -sp4 //自定義的選項文件
env-vc6.lnt //用來設置編輯環境的配置文件
-id:\vc6\vc98\include //include目錄
如果把PC-Lint集成到某個編輯環境中,那么輸入的格式必須和對應環境吻合,才能保證在鼠標點擊(或雙擊)錯誤消息條目時,可自動定位到對應源代碼行,這類配置放置在env-xxx.lnt文件中,這些文件在PC-lint安裝時,就自帶的,在.\Lnt子目錄下,如VC6是env-vc6.lnt,SourceInsight是env-si.lnt。我們只需找到與自己的編輯環境相匹配的env-xxx.lnt文件,然后將它寫入std.lnt中即可。
源代碼在編輯環境中鏈接通過后,我們就可以使用PC-Lint命令做靜態檢查了。它可以說是一種更加嚴格的編譯器,不僅可以查出一般的語法錯誤,還可以檢查出那些雖然合乎語法要求,但很可能是潛在的、不易發現的錯誤。
PC-Lint告警分為0~4級,其中0級是內部錯誤或致命錯誤,1級告警是句法錯誤,2級告警是警告,3級是信息,4級是可選的,4級缺省是不打開的。告警級別定義如下表,
C |
C++ |
Warning Level |
|
Syntax Errors |
1 - 199 |
1001 - 1199 |
1 |
Internal Errors |
200 - 299 |
|
0 |
Fatal Errors |
300 - 399 |
|
0 |
Warnings |
400 - 699 |
1400 - 1699 |
2 |
Informational |
700 - 899 |
1700 - 1899 |
3 |
Elective Notes |
900 - 999 |
1900 - 1999 |
4 |
任何事物都有兩面性,PC-Lint也不例外。它也會經常有一些誤報,為了消除這些誤報,我們不得不使用一些PC-Lint選項來屏蔽這些告警。常用選項如下:
- -i選項
這個選項主要是用來設置include路徑的
如:-iD:\VC6\VC98\Include
- -e#選項
這個選項主要是用來屏蔽告警號為#的告警
如:-e818 表示不顯示告警號為818的告警
- -esym(#, 符號名)選項
這個選項主要是用來屏蔽告警號為#的某個符號的告警,
如-esym(39, std)
- -emacro(#,宏名稱)選項
這個選項主要是用來屏蔽告警號為#的某個宏的告警
其中,0~2級告警都不能使用-e選項進行屏蔽,只能使用-esym,-emacro,-sem之類的選項進行屏蔽;3級告警要根據具體情況,有些可以使用-e選項進行屏蔽,有些不可以。
通過對PC-Lint告警的分析,我們總結出一些C++編寫規范。
- 過分依賴C表達式中的運算符優先規則; 例如:else if (m_nSize+STEP_KEYCOUNT > m_nMaxCount), 最好能加個括號。
- 變量定義了,卻沒什么作用。
- 在構造函數中盡量不要分配內存,否則會有告警error 1732。
- 函數可以申明為const類型,通常都是一些沒有修改成員變量的函數會有這類告警error 1762。
- 成員變量使用前沒有初始化。
- 類指針成員沒有釋放,尤其是異常返回的時候,忘記釋放指針成員,這很容易引起內存泄漏。
- 在使用指針成員時,沒有判斷是否為空指針。
- 設計階段,就想好接口變量類型,減少類型轉換的頻率。
- 判斷條件有問題,這就是邏輯錯誤。運用PC-lint也很難檢查出來,需要開發人員特別小心。
總之,PC-lint是個簡單易用的代碼靜態檢查工具。它可以幫助開發人員,檢查出語法邏輯上的錯誤,還能夠提出程序在空間利用、運行效率上的改進點。它也可以幫助測試人員,檢查源碼是否符合C/C++代碼編寫規范,是否有語法錯誤,如不匹配的參數、未使用過的變量、空指針的引用等。如果測試人員水平高的話,也可以找出代碼邏輯性、合理性上的問題,如:不適當的循環嵌套和分支嵌套、不允許的遞歸和可疑的計算等;還可以利用靜態檢查的結果做進一步的查錯,且能為測試用例的編寫提供些許的指導。