靜態代碼分析工具簡介

靜態代碼分析工具簡介

什麼是靜態代碼分析

靜態代碼分析是指無需運行被測代碼,僅通過分析或檢查源程序的語法、結構、過程、接口等來檢查程序的正確性,找出代碼隱藏的錯誤和缺陷,如參數不匹配,有歧義的嵌套語句,錯誤的遞歸,非法計算,可能出現的空指針引用等等。

在軟件開發過程中,靜態代碼分析往往先於動態測試之前進行,同時也可以作爲制定動態測試用例的參考。統計證明,在整個軟件開發生命週期中,30% 至 70% 的代碼邏輯設計和編碼缺陷是可以通過靜態代碼分析來發現和修復的。

但是,由於靜態代碼分析往往要求大量的時間消耗和相關知識的積累,因此對於軟件開發團隊來說,使用靜態代碼分析工具自動化執行代碼檢查和分析,能夠極大地提高軟件可靠性並節省軟件開發和測試成本。

靜態代碼分析工具的優勢

  1. 幫助程序開發人員自動執行靜態代碼分析,快速定位代碼隱藏錯誤和缺陷。
  2. 幫助代碼設計人員更專注於分析和解決代碼設計缺陷。
  3. 顯著減少在代碼逐行檢查上花費的時間,提高軟件可靠性並節省軟件開發和測試成本。

三款主流靜態源代碼安全檢測工具比較(付費)

Fortify SCA(Source Code Analysis)

Fortify Software公司是一家總部位於美國硅谷,致力於提供應用軟件安全開發工具和管理方案的廠商。Fortify爲應用軟件開發組織、安全審計人員和應用 安全管理人員提供工具並確立最佳的應用軟件安全實踐和策略,幫助他們在軟件開發生命週期中花最少的時間和成本去識別和修復軟件源代碼中的安全隱患。 Fortify SCA是Fortify360產品套裝中的一部分,它使用fortify公司特有的X-Tier Dataflow™ analysis技術去檢測軟件安全問題。

優點:目前全球最大靜態源代碼檢測廠商、支持語言最多

缺點:價格昂貴、使用不方便

Checkmarx CxSuite

Checkmarx 是以色列的一家高科技軟件公司。它的產品CheckmarxCxSuite專門設計爲識別、跟蹤和修復軟件源代碼上的技術和邏輯方面的安全風險。首創了以查詢語言定位代碼安全問題,其採用獨特的詞彙分析技術和CxQL專利查詢技術來掃描和分析源代碼中的安全漏洞和弱點。

優點:利用CxQL 查詢語言自定義規則

缺點:輸出報告不夠美觀、語言支持種類不全面

Armorize CodeSecure

阿碼科技成立於2006年,總部設立於美國加州聖克拉拉市,研發中心位於臺灣的南港軟件工業園區。阿碼科技提供全方位網絡安全解決方案,捍衛企業免於受到黑客利用 Web 應用程序的漏洞所發動的攻擊。阿碼科技 CodeSecure可有效地協助企業與開發人員在軟件開發過程及項目上線後找出 Web 應用程序風險,並清楚交代風險的來龍去脈 (如何進入程序,如何造成問題) 。CodeSecure內建語法剖析功能無需依賴編譯環境,任何人員均可利用 Web操作與集成開發環境雙接口,找出存在信息安全問題的源代碼,並提供修補建議進行調整。CodeSecure依託於自行開發的主機進行遠程源代碼檢 測,在保證速度穩定的同時方便用戶進行Web遠程操作。

優點:Web結合硬件,速度快、獨具特色的深度分析

缺點:支持語言種類較少、價格不菲

對比

SCA CxSuite CodeSecure
廠商 Fortify Software Checkmarx 阿碼科技
支持語言 Java,JSP,ASP.NET,C#, VB.NET,C,C++,COBOL, ColdFusion,Transact-SQL, PL/SQL,JavaScript/Ajax, Classic,ASP,VBScript,VB6,PHP JAVA、ASP.NET(C#、VB.NET)、JavaScript、Jscript、C/C++、APEX ASP.NET(C#、VB.NET)、ASP、JAVA、PHP
風險種類 400種 300種 參考CWE
風險類型參考來源 CWE、OWASP CWE、OWASP CWE、OWASP
漏報率 最低
誤報率 稍高
是否支持SaaS
軟硬件類型 純軟件 純軟件 Web結合硬件設備
運行平臺 無限制 WindowsNET Framework 2.0 無限制
運行速度 取決於電腦配置速度不定 取決於電腦配置速度不定 由主機配置決定速度恆定
報告格式 PDF PDF、XML、CSV、HTML Web、PDF
報告內容 完整按照風險級別不同分爲多個文件 核心內容完整掃描信息等缺失 非常完整但修改建議放於最後
報價 100萬/軟件 70萬/軟件 100萬/軟硬件
性價比

Java 靜態代碼分析理論基礎和主要技術

  • 缺陷模式匹配:缺陷模式匹配事先從代碼分析經驗中收集足夠多的共性缺陷模式,將待分析代碼與已有的共性缺陷模式進行模式匹配,從而完成軟件的安全分析。這種方式的優點是簡單方便,但是要求內置足夠多缺陷模式,且容易產生誤報。
  • 類型推斷:類型推斷技術是指通過對代碼中運算對象類型進行推理,從而保證代碼中每條語句都針對正確的類型執行。這種技術首先將預定義一套類型機制,包括類 型等價、類型包含等推理規則,而後基於這一規則進行推理計算。類型推斷可以檢查代碼中的類型錯誤,簡單,高效,適合代碼缺陷的快速檢測。
  • 模型檢查:模型檢驗建立於有限狀態自動機的概念基礎之上,這一理論將被分析代碼抽象爲一個自動機系統,並且假設該系統是有限狀態的、或者是可以通過抽象歸 結爲有限狀態。模型檢驗過程中,首先將被分析代碼中的每條語句產生的影響抽象爲一個有限狀態自動機的一個狀態,而後通過分析有限狀態機從而達到代碼分析的 目的。模型檢驗主要適合檢驗程序併發等時序特性,但是對於數據值域數據類型等方面作用較弱。
  • 數據流分析:數據流分析也是一種軟件驗證技術,這種技術通過收集代碼中引用到的變量信息,從而分析變量在程序中的賦值、引用以及傳遞等情況。對數據流進行 分析可以確定變量的定義以及在代碼中被引用的情況,同時還能夠檢查代碼數據流異常,如引用在前賦值在後、只賦值無引用等。數據流分析主要適合檢驗程序中的 數據域特性。

現有主流 Java 靜態分析工具(開源)

Checkstyle

Checkstyle 是 SourceForge 的開源項目,通過檢查對代碼編碼格式,命名約定,Javadoc,類設計等方面進行代碼規範和風格的檢查,從而有效約束開發人員更好地遵循代碼編寫規範。

Checkstyle 提供了支持大多數常見 IDE 的插件,文本主要使用 Eclipse 中的 Checkstyle 插件。如下圖 1 所示,Checkstyle 對代碼進行編碼風格檢查,並將檢查結果顯示在 Problems 視圖中。圖中,代碼編輯器中每個放大鏡圖標表示一個 Checkstyle 找到的代碼缺陷。開發人員可通過在 Problems 視圖中查看錯誤或警告詳細信息。

圖 1. 使用 Checkstyle 進行編碼風格檢查
圖 1. 使用 Checkstyle 進行編碼風格檢查

此外,Checkstyle 支持用戶根據需求自定義代碼檢查規範,在下圖 2 中的配置面板中,用戶可以在已有檢查規範如命名約定,Javadoc,塊,類設計等方面的基礎上添加或刪除自定義檢查規範。

圖 2. 使用 Checkstyle 添加自定義代碼檢查規範 圖 2. 使用 Checkstyle 添加自定義代碼檢查規範

FindBugs

FindBugs 是由馬里蘭大學提供的一款開源 Java 靜態代碼分析工具。FindBugs 通過檢查類文件或 JAR 文件,將字節碼與一組缺陷模式進行對比從而發現代碼缺陷,完成靜態代碼分析。FindBugs 既提供可視化 UI 界面,同時也可以作爲 Eclipse 插件使用。文本將主要使用將 FindBugs 作爲 Eclipse 插件。在安裝成功後會在 eclipse 中增加 FindBugs perspective,用戶可以對指定 Java 類或 JAR 文件運行 FindBugs,此時 FindBugs 會遍歷指定文件,進行靜態代碼分析,並將代碼分析結果顯示在 FindBugs perspective 的 bugs explorer 中,如下圖 3 所示:

圖 3. 使用 FindBugs 進行靜態代碼分析
圖 3. 使用 FindBugs 進行靜態代碼分析

此外,FindBugs 還爲用戶提供定製 Bug Pattern 的功能。用戶可以根據需求自定義 FindBugs 的代碼檢查條件,如下圖 4 所示:

圖 4. 使用 FindBugs 添加自定義代碼檢查規範
圖 4. 使用 FindBugs 添加自定義代碼檢查規範

PMD

PMD 是由 DARPA 在 SourceForge 上發佈的開源 Java 代碼靜態分析工具。PMD 通過其內置的編碼規則對 Java 代碼進行靜態檢查,主要包括對潛在的 bug,未使用的代碼,重複的代碼,循環體創建新對象等問題的檢驗。PMD 提供了和多種 Java IDE 的集成,例如 Eclipse,IDEA,NetBean 等。本文主要使用 PMD 以插件方式與 Eclipse 集成。如下圖 5 所示:在 Violations Overview 視圖中,按照代碼缺陷嚴重性集中顯示了 PMD 靜態代碼分析的結果。

圖 5. 使用 PMD 進行靜態代碼分析
圖 5. 使用 PMD 進行靜態代碼分析

圖 6. 使用 PMD 添加自定義代碼檢查規範
圖 6. 使用 PMD 添加自定義代碼檢查規範

Jtest

Jtest 是 Parasoft 公司推出的一款針對 Java 語言的自動化代碼優化和測試工具,Jtest 的靜態代碼分析功能能夠按照其內置的超過 800 條的 Java 編碼規範自動檢查並糾正這些隱蔽且難以修復的編碼錯誤。同時,還支持用戶自定義編碼規則,幫助用戶預防一些特殊用法的錯誤。Jtest 提供了基於 Eclipse 的插件安裝。Jtest 支持開發人員對 Java 代碼進行編碼規範檢查,並在 Jtask 窗口中集中顯示檢查結果,如下圖 7 所示:

圖 7. 使用 Jtest 進行靜態代碼分析
圖 7. 使用 Jtest 進行靜態代碼分析

圖 8. 使用 Jtest 添加自定義代碼檢查規範
圖 8. 使用 Jtest 添加自定義代碼檢查規範

Java 靜態分析工具對比

本章節將從以下幾個方面對上述 Java 靜態分析工具進行比較:

應用技術及分析對象

下表 1 列出了不同工具的分析對象及應用技術對比:

表 1. 不同工具的分析對象及應用技術對比

Java 靜態分析工具 分析對象 應用技術
Checkstyle Java 源文件 缺陷模式匹配
FindBugs 字節碼 缺陷模式匹配;數據流分析
PMD Java 源代碼 缺陷模式匹配
Jtest Java 源代碼 缺陷模式匹配;數據流分析

內置編程規範

Checkstyle:

  • Javadoc 註釋:檢查類及方法的 Javadoc 註釋
  • 命名約定:檢查命名是否符合命名規範
  • 標題:檢查文件是否以某些行開頭
  • Import 語句:檢查 Import 語句是否符合定義規範
  • 代碼塊大小,即檢查類、方法等代碼塊的行數
  • 空白:檢查空白符,如 tab,回車符等
  • 修飾符:修飾符號的檢查,如修飾符的定義順序
  • 塊:檢查是否有空塊或無效塊
  • 代碼問題:檢查重複代碼,條件判斷,魔數等問題
  • 類設計:檢查類的定義是否符合規範,如構造函數的定義等問題

FindBugs:

  • Bad practice 壞的實踐:常見代碼錯誤,用於靜態代碼檢查時進行缺陷模式匹配
  • Correctness 可能導致錯誤的代碼,如空指針引用等
  • 國際化相關問題:如錯誤的字符串轉換
  • 可能受到的惡意攻擊,如訪問權限修飾符的定義等
  • 多線程的正確性:如多線程編程時常見的同步,線程調度問題。
  • 運行時性能問題:如由變量定義,方法調用導致的代碼低效問題。

PMD:

  • 可能的 Bugs:檢查潛在代碼錯誤,如空 try/catch/finally/switch 語句
  • 未使用代碼(Dead code):檢查未使用的變量,參數,方法
  • 複雜的表達式:檢查不必要的 if 語句,可被 while 替代的 for 循環
  • 重複的代碼:檢查重複的代碼
  • 循環體創建新對象:檢查在循環體內實例化新對象
  • 資源關閉:檢查 Connect,Result,Statement 等資源使用之後是否被關閉掉

Jtest

  • 可能的錯誤:如內存破壞、內存泄露、指針錯誤、庫錯誤、邏輯錯誤和算法錯誤等
  • 未使用代碼:檢查未使用的變量,參數,方法
  • 初始化錯誤:內存分配錯誤、變量初始化錯誤、變量定義衝突
  • 命名約定:檢查命名是否符合命名規範
  • Javadoc 註釋:檢查類及方法的 Javadoc 註釋
  • 線程和同步:檢驗多線程編程時常見的同步,線程調度問題
  • 國際化問題:
  • 垃圾回收:檢查變量及 JDBC 資源是否存在內存泄露隱患

錯誤檢查能力

爲比較上述 Java 靜態分析工具的代碼缺陷檢測能力,本文將使用一段示例代碼進行試驗,示例代碼中將涵蓋我們開發中的幾類常見錯誤,如引用操作、對象操作、表達式複雜化、數 組使用、未使用變量或代碼段、資源回收、方法調用及代碼設計幾個方面。最後本文將分別記錄在默認檢查規範設置下,不同工具對該示例代碼的分析結果。以下爲 示例代碼 Test.java。其中,代碼的註釋部分列舉了代碼中可能存在的缺陷。

清單 1. Test.java 示例代碼

package Test;
import java.io.*;
public class Test {
    /**
     * Write the bytes from input stream to output stream.
     * The input stream and output stream are not closed.
     * @param is
     * @param os
     * @throws IOException
     */
    public  boolean copy(InputStream is, OutputStream os) throws IOException {
        int count = 0;
        //缺少空指針判斷
        byte[] buffer = new byte[1024];
        while ((count = is.read(buffer)) >= 0) {
            os.write(buffer, 0, count);
        }
        //未關閉I/O流
        return true;
    }
    /**
     * 
     * @param a
     * @param b
     * @param ending
     * @return copy the elements from a to b, and stop when meet element ending
     */
    public void copy(String[] a, String[] b, String ending)
    {
        int index;
        String temp = null;
        //空指針錯誤
        System.out.println(temp.length());
        //未使用變量
        int length=a.length;
        for(index=0; index < a.length; index++)
        {
            //多餘的if語句
            if(true)
            {
                //對象比較 應使用equals
                if(temp==ending)
                {
                    break;
                }
                //缺少 數組下標越界檢查
                b[index]=temp;
            }
        }
    }
    /**
     * 
     * @param file
     * @return file contents as string; null if file does not exist
     */
    public  void  readFile(File file) {
        InputStream is = null;
        OutputStream os = null;
            try {
                is = new BufferedInputStream(new FileInputStream(file));
                os = new ByteArrayOutputStream();
                //未使用方法返回值
                copy(is,os);
                is.close();
                os.close();
            } catch (IOException e) {
                //可能造成I/O流未關閉
                e.printStackTrace();
            } 
            finally
            {
                //空的try/catch/finally塊
            }
    }
}

通過以上測試代碼,我們對已有 Java 靜態代碼分析工具的檢驗結果做了如下比較,如下表 2 所示。
表 2. Java 靜態代碼分析工具對比

代碼缺陷分類 示例 Checkstyle FindBugs PMD Jtest
引用操作 空指針引用
對象操作 對象比較(使用 == 而不是 equals)
表達式複雜化 多餘的 if 語句
數組使用 數組下標越界
未使用變量或代碼段 未使用變量
資源回收 I/O 未關閉
方法調用 未使用方法返回值
代碼設計 空的 try/catch/finally 塊

由表中可以看出幾種工具對於代碼檢查各有側重。其中,Checkstyle 更偏重於代碼編寫格式,及是否符合編碼規範的檢驗,對代碼 bug 的發現功能較弱;而 FindBugs,PMD,Jtest 着重於發現代碼缺陷。在對代碼缺陷檢查中,這三種工具在針對的代碼缺陷類別也各有不同,且類別之間有重疊。

總結

本文分別從功能、特性和內置編程規範等方面詳細介紹了包括 Checkstyle,FindBugs,PMD,Jtest 在內的四種主流 Java 靜態代碼分析工具,並通過一段 Java 代碼示例對這四種工具的代碼分析能力進行比較。由於這四種工具內置編程規範各有不同,因此它們對不同種類的代碼問題的發現能力也有所不同。其中 Checkstyle 更加偏重於代碼編寫格式檢查,而 FindBugs,PMD,Jtest 着重於發現代碼缺陷。最後,希望本文能夠幫助 Java 軟件開發和測試人員進一步瞭解以上四種主流 Java 靜態分析工具,並幫助他們根據需求選擇合適的工具。

現有主流 C/C++靜態分析工具(開源)

splint

splint介紹

splint是一個靜態檢查C語言程序安全弱點和編寫錯誤的工具。splint會進行多種常規檢查,包括未使 用的變量,類型不一致,使用未定義變量,無法執行的代碼,忽略返回值,執行路徑未返回,無限循環等錯誤。同 時通過在源碼中添加註記給出的附加信息,使其可以進行功能更加強大的檢查。而註記,則是對文件中的函數、變 量、參數以及類型進行假定的一種的程式化的註釋。

splint的安裝

官網:http://splint.org/

最新版本:Splint Version 3.1.2

支持平臺

windows(舊版本支持)

[外鏈圖片轉存失敗(img-ALXTzv9B-1569412951252)(C:%5CUsers%5Chaizhou.song%5CDesktop%5C%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7%5Cjava%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7.assets%5C1569382210558.png)]

Linux:

sudo apt-get install splint

[外鏈圖片轉存失敗(img-a9Ay89CE-1569412951252)(C:%5CUsers%5Chaizhou.song%5CDesktop%5C%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7%5Cjava%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7.assets%5C1569382151967.png)]

可檢查錯誤類型

  1. Dereferencing a possibly null pointer
  2. Using possibly undefined storage or returning storage that is not properly defined
  3. Type mismatches, with greater precision and flexibility than provided by C compilers
  4. Violations of information hiding
  5. Memory management errors including uses of dangling references and memory leaks
  6. Dangerous aliasing
  7. Modifications and global variable uses that are inconsistent with specified interfaces
  8. Problematic control flow such as likely infinite loops
  9. Buffer overflow vulnerabilities
  10. Dangerous macro implementations or invocations
  11. Violations of customized naming conventions

Cppcheck

介紹

Cppcheck is a static analysis tool for C/C++ code. It provides unique code analysis to detect bugs and focuses on detecting undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code (i.e. have very few false positives).

安裝

官網:http://cppcheck.sourceforge.net/

最新版本:Cppcheck 1.89

支持平臺

windows

[外鏈圖片轉存失敗(img-uQrjFeSm-1569412951253)(C:%5CUsers%5Chaizhou.song%5CDesktop%5C%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7%5Cjava%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7.assets%5C1569382268226.png)]

linux:

sudo apt-get install cppcheck

[外鏈圖片轉存失敗(img-h68RzBzI-1569412951253)(C:%5CUsers%5Chaizhou.song%5CDesktop%5C%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7%5Cjava%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7.assets%5C1569382310710.png)]

可檢查錯誤類型

# get list of checks
cppcheck --doc

64-bit portability

Check if there is 64-bit portability issues:

  • assign address to/from int/long

  • casting address from/to integer when returning from function

    Assert

    Warn if there are side effects in assert statements (since this cause different behaviour in debug/release builds).

    Auto Variables

    A pointer to a variable is only valid as long as the variable is in scope.

    Check:

  • returning a pointer to auto or temporary variable

  • assigning address of an variable to an effective parameter of a function

  • returning reference to local/temporary variable

  • returning address of function parameter

  • suspicious assignment of pointer argument

  • useless assignment of function argument

    Boolean

    Boolean type checks

  • using increment on boolean

  • comparison of a boolean expression with an integer other than 0 or 1

  • comparison of a function returning boolean value using relational operator

  • comparison of a boolean value with boolean value using relational operator

  • using bool in bitwise expression

  • pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)

  • Assigning bool value to pointer or float

    Boost usage

    Check for invalid usage of Boost:

  • container modification during BOOST_FOREACH

    Bounds checking

    Out of bounds checking:

  • Array index out of bounds detection by value flow analysis

  • Dangerous usage of strncat()

  • char constant passed as size to function like memset()

  • strncpy() leaving string unterminated

  • Accessing array with negative index

  • Unsafe usage of main(argv, argc) arguments

  • Accessing array with index variable before checking its value

  • Check for large enough arrays being passed to functions

  • Allocating memory with a negative size

    Check function usage

    Check function usage:

  • return value of certain functions not used

  • invalid input values for functions

  • Warn if a function is called whose usage is discouraged

  • memset() third argument is zero

  • memset() with a value out of range as the 2nd parameter

  • memset() with a float as the 2nd parameter

    Class

    Check the code for each class.

  • Missing constructors and copy constructors

  • Constructors which should be explicit

  • Are all variables initialized by the constructors?

  • Are all variables assigned by ‘operator=’?

  • Warn if memset, memcpy etc are used on a class

  • Warn if memory for classes is allocated with malloc()

  • If it’s a base class, check that the destructor is virtual

  • Are there unused private functions?

  • ‘operator=’ should return reference to self

  • ‘operator=’ should check for assignment to self

  • Constness for member functions

  • Order of initializations

  • Suggest usage of initialization list

  • Initialization of a member with itself

  • Suspicious subtraction from ‘this’

  • Call of pure virtual function in constructor/destructor

  • Duplicated inherited data members

  • If ‘copy constructor’ defined, ‘operator=’ also should be defined and vice versa

  • Check that arbitrary usage of public interface does not result in division by zero

    Condition

    Match conditions with assignments and other conditions:

  • Mismatching assignment and comparison => comparison is always true/false

  • Mismatching lhs and rhs in comparison => comparison is always true/false

  • Detect usage of | where & should be used

  • Detect matching ‘if’ and ‘else if’ conditions

  • Mismatching bitand (a &= 0xf0; a &= 1; => a = 0)

  • Opposite inner condition is always false

  • Identical condition after early exit is always false

  • Condition that is always true/false

  • Mutual exclusion over || always evaluating to true

  • Comparisons of modulo results that are always true/false.

  • Known variable values => condition is always true/false

  • Invalid test for overflow (for example ‘ptr+u < ptr’). Condition is always false unless there is overflow, and overflow is undefined behaviour.

    Exception Safety

    Checking exception safety

  • Throwing exceptions in destructors

  • Throwing exception during invalid state

  • Throwing a copy of a caught exception instead of rethrowing the original exception

  • Exception caught by value instead of by reference

  • Throwing exception in noexcept, nothrow(), attribute((nothrow)) or __declspec(nothrow) function

  • Unhandled exception specification when calling function foo()

    IO using format string

    Check format string input/output operations.

  • Bad usage of the function ‘sprintf’ (overlapping data)

  • Missing or wrong width specifiers in ‘scanf’ format string

  • Use a file that has been closed

  • File input/output without positioning results in undefined behaviour

  • Read to a file that has only been opened for writing (or vice versa)

  • Repositioning operation on a file opened in append mode

  • Using fflush() on an input stream

  • Invalid usage of output stream. For example: ‘std::cout << std::cout;’

  • Wrong number of arguments given to ‘printf’ or ‘scanf;’

    Leaks (auto variables)

    Detect when a auto variable is allocated but not deallocated or deallocated twice.

    Memory leaks (address not taken)

    Not taking the address to allocated memory

    Memory leaks (class variables)

    If the constructor allocate memory then the destructor must deallocate it.

    Memory leaks (function variables)

    Is there any allocated memory when a function goes out of scope

    Memory leaks (struct members)

    Don’t forget to deallocate struct members

    Null pointer

    Null pointers

  • null pointer dereferencing

  • undefined null pointer arithmetic

    Other

    Other checks

  • division with zero

  • scoped object destroyed immediately after construction

  • assignment in an assert statement

  • free() or delete of an invalid memory location

  • bitwise operation with negative right operand

  • provide wrong dimensioned array to pipe() system command (–std=posix)

  • cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF

  • race condition with non-interlocked access after InterlockedDecrement() call

  • expression ‘x = x++;’ depends on order of evaluation of side effects

  • either division by zero or useless condition

  • access of moved or forwarded variable.

  • redundant data copying for const variable

  • subsequent assignment or copying to a variable or buffer

  • passing parameter by value

  • Passing NULL pointer to function with variable number of arguments leads to UB.

  • C-style pointer cast in C++ code

  • casting between incompatible pointer types

  • Incomplete statement

  • check how signed char variables are used

  • variable scope can be limited

  • unusual pointer arithmetic. For example: “abc” + ‘d’

  • redundant assignment, increment, or bitwise operation in a switch statement

  • redundant strcpy in a switch statement

  • Suspicious case labels in switch()

  • assignment of a variable to itself

  • Comparison of values leading always to true or false

  • Clarify calculation with parentheses

  • suspicious comparison of ‘\0’ with a char* variable

  • duplicate break statement

  • unreachable code

  • testing if unsigned variable is negative/positive

  • Suspicious use of ; at the end of ‘if/for/while’ statement.

  • Array filled incompletely using memset/memcpy/memmove.

  • NaN (not a number) value used in arithmetic expression.

  • comma in return statement (the comma can easily be misread as a semicolon).

  • prefer erfc, expm1 or log1p to avoid loss of precision.

  • identical code in both branches of if/else or ternary operator.

  • redundant pointer operation on pointer like &*some_ptr.

  • find unused ‘goto’ labels.

  • function declaration and definition argument names different.

  • function declaration and definition argument order different.

    STL usage

    Check for invalid usage of STL:

  • out of bounds errors

  • misuse of iterators when iterating through a container

  • mismatching containers in calls

  • dereferencing an erased iterator

  • for vectors: using iterator/pointer after push_back has been used

  • optimisation: use empty() instead of size() to guarantee fast code

  • suspicious condition when using find

  • redundant condition

  • common mistakes when using string::c_str()

  • using auto pointer (auto_ptr)

  • useless calls of string and STL functions

  • dereferencing an invalid iterator

  • reading from empty STL container

    Sizeof

    sizeof() usage checks

  • sizeof for array given as function argument

  • sizeof for numeric given as function argument

  • using sizeof(pointer) instead of the size of pointed data

  • look for ‘sizeof sizeof …’

  • look for calculations inside sizeof()

  • look for suspicious calculations with sizeof()

  • using ‘sizeof(void)’ which is undefined

    String

    Detect misusage of C-style strings:

  • overlapping buffers passed to sprintf as source and destination

  • incorrect length arguments for ‘substr’ and ‘strncmp’

  • suspicious condition (runtime comparison of string literals)

  • suspicious condition (string literals as boolean)

  • suspicious comparison of a string literal with a char* variable

  • suspicious comparison of ‘\0’ with a char* variable

  • overlapping strcmp() expression

    Type

    Type checks

  • bitwise shift by too many bits (only enabled when --platform is used)

  • signed integer overflow (only enabled when --platform is used)

  • dangerous sign conversion, when signed value can be negative

  • possible loss of information when assigning int result to long variable

  • possible loss of information when returning int result as long return value

  • float conversion overflow

    Uninitialized variables

    Uninitialized variables

  • using uninitialized local variables

  • using allocated data before it has been initialized

  • using dead pointer

    Unused functions

    Check for functions that are never called

    UnusedVar

    UnusedVar checks

  • unused variable

  • allocated but unused variable

  • unred variable

  • unassigned variable

  • unused struct member

    Using postfix operators

    Warn if using postfix operators ++ or – rather than prefix operator

    Vaarg

    Check for misusage of variable argument lists:

  • Wrong parameter passed to va_start()

  • Reference passed to va_start()

  • Missing va_end()

  • Using va_list before it is opened

  • Subsequent calls to va_start/va_copy()

錯誤檢查能力對比

清單 1. test_1.c 示例代碼

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
        //類型轉換警告
        unsigned char ch = 128;
        signed char sch = ch;
	    printf("%d", sch);
    
        //數組溢出
        int a[12];
        a[12] = 12; 

        //空指針引用
        int *b = NULL;
        (*b)++; 

        // 野指針引用
        int *q = (int*)malloc(1000*sizeof(int)); 
        free(q);
        (*q)++;

        // 內存泄漏 p沒free
        int *p = (int*)malloc(1000*sizeof(int));            
         
        //return 0;  函數返回值
}

清單 2. test_2.c 示例代碼

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
//死循環
        while (1) 
            printf("hello world!\n");

        return 0;
}//死循環會影響其他檢測結果 原因未知

通過以上測試代碼,我們對已有 C 靜態代碼分析工具的檢驗結果做了如下比較,如下表 2 所示。

表 1.C 靜態代碼分析工具對比

代碼問題 splint Cppcheck
類型轉換
數組溢出
空指針引用
野指針引用
內存泄露
函數返回值
死循環
變量未使用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章