cppcheck,代碼簡單分析,以及實現一個簡單的模塊


經過半天的分析和了解,大致明白了這個工具的使用方法和原理。

這個工具,會將一個源文件(目前我是用單一源文件測試的,沒有使用目錄測試),

每一個有效符號或者元素都解析出來,之后儲存在一個大list里面,供后續模塊檢測時使用,

但是一些特殊的元素,不會被列入list,如調用約定(__stdcall 此類等等),其他應該還有,但是還沒使用到,

目前看到的情況是,整個文件所有內容全部都被放到了一個list 里面,挺痛苦的。

內置模塊部分,其實它內置了很多功能

 

 

 

一堆check,很方便我來學習,據此我也寫出了一個簡單的check模塊,代碼如下

 1 #pragma once
 2 
 3 #include "check.h"
 4 #include "ctu.h"
 5 
 6 #include <cstddef>
 7 #include <list>
 8 #include <map>
 9 #include <string>
10 #include <vector>
11 
12 class CPPCHECKLIB CheckZooFrame : public Check {
13 public:
14 
15     /** This constructor is used when registering the CheckClass */
16     CheckZooFrame() : Check(myName()) {
17     }
18 
19     /** This constructor is used when running checks. */
20     CheckZooFrame(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
21         : Check(myName(), tokenizer, settings, errorLogger) {
22     }
23 
24     void runChecks(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) OVERRIDE;
25 
26     void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const OVERRIDE;
27 
28     /** @brief Parse current TU and extract file info */
29     Check::FileInfo* getFileInfo(const Tokenizer* tokenizer, const Settings* settings) const OVERRIDE;
30 
31     /** @brief Analyse all file infos for all TU */
32     bool analyseWholeProgram(const CTU::FileInfo* ctu, const std::list<Check::FileInfo*>& fileInfo, const Settings& settings, ErrorLogger& errorLogger) OVERRIDE;
33 
34 private:
35 
36     /** data for multifile checking */
37     class MyFileInfo : public Check::FileInfo {
38     public:
39         /** unsafe array index usage */
40         std::list<CTU::FileInfo::UnsafeUsage> unsafeArrayIndex;
41 
42         /** unsafe pointer arithmetics */
43         std::list<CTU::FileInfo::UnsafeUsage> unsafePointerArith;
44 
45         /** Convert MyFileInfo data into xml string */
46         std::string toString() const OVERRIDE {
47             return "Zoos";
48         }
49     };
50 
51     Check::FileInfo* loadFileInfoFromXml(const tinyxml2::XMLElement* xmlElement) const OVERRIDE;
52 
53 
54     static std::string myName() {
55         return "Zoo checking";
56     }
57 
58     std::string classInfo() const OVERRIDE {
59         return "Zoo Check Frame\n";
60     }
61 };
 1 #include "check_zoo.h"
 2 #include "check.h"
 3 
 4 namespace {
 5     CheckZooFrame instance;
 6 }
 7 
 8 
 9 
10 static const CWE CWE_POINTER_ARITHMETIC_OVERFLOW(758U);
11 
12 
13 void CheckZooFrame::runChecks(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) {
14     printf("FILE [%s] LINE [%d] Function [%s] \n", __FILE__, __LINE__, tokenizer->tokens()->next()->str().c_str());
15     CheckZooFrame c(tokenizer, settings, errorLogger);
16     c.reportError(tokenizer->tokens(), Severity::portability, "Zoo檢測點", "Zoo框架", CWE_POINTER_ARITHMETIC_OVERFLOW, false);
17 
18     for (const Token* tok = tokenizer->tokens(); tok; tok = tok->next())
19     {
20         printf("%s ", tok->str().c_str());
21         if (tok->str() == "{" || tok->str() == "}" || tok->str() == ";")
22         {
23             printf("\n");
24         }
25     }
26 }
27 
28 void CheckZooFrame::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const {
29     printf("FILE [%s] LINE [%d] \n", __FILE__, __LINE__);
30 }
31 
32 /** @brief Parse current TU and extract file info */
33 Check::FileInfo* CheckZooFrame::getFileInfo(const Tokenizer* tokenizer, const Settings* settings) const {
34     printf("FILE [%s] LINE [%d] \n", __FILE__, __LINE__);
35     return NULL;
36 }
37 
38 /** @brief Analyse all file infos for all TU */
39 bool CheckZooFrame::analyseWholeProgram(const CTU::FileInfo* ctu, const std::list<Check::FileInfo*>& fileInfo, const Settings& settings, ErrorLogger& errorLogger) {
40     printf("FILE [%s] LINE [%d] \n", __FILE__, __LINE__);
41     return true;
42 }
43 
44 
45 Check::FileInfo* CheckZooFrame::loadFileInfoFromXml(const tinyxml2::XMLElement* xmlElement) const {
46     printf("FILE [%s] LINE [%d] \n", __FILE__, __LINE__);
47     return NULL;
48 }

 

擴展性還是非常強的,我的代碼,幾乎全部都是對照其他模塊來寫的,

而且接口也非常簡單,很友好。

 

這里簡單地解釋一下吧。

cppcheck的模塊系統屬於構造時直接靠全局變量串起來的這種模式(相似的可以看llvm,clang的命令行系統,也是這么串起來的),

優點是簡單方便,只要繼承了父類,然后實例化一個自己,就解決了問題,

缺點是,很多關鍵信息無法在初次構造時就獲取到,所以使用時有點麻煩。

本人在編寫這個簡單模塊的時候,就遇到了這個小麻煩,不過還是解決了。

主要體現在,錯誤上報的部分。

整個cppcheck框架,其實比較強大,它實際上真的僅僅是作為一個普通框架來執行的,

內部功能通過一個個模塊,一次次傳遞參數,一個個reportError來列出。

 

以 CheckZooFrame 為例,

首先需要實現若干虛函數,繼承於 check 父類,

然后定義一個全局變量,供初始化的時候,掛接自己,

但是這時候,由於自己無法獲取到任何關鍵信息,所以內部變量初始化全部都是空,

即CPP代碼中第五行。

掛接了自己之后,最重要的函數,其實只有一個,是runcheck,

這個函數會被外面check管理器直接調用,會傳入一系列的參數,

讓當前模塊來檢測是否有需要檢測的異常,

如果有的話,則通過reportError上報。

這時候就有問題了,reportError上報需要知道當前的代碼list,但是初始化的時候已經全都是空了,沒有list,

怎么辦,那就只能在自己內部重新創建個局部變量,構造時讓它有list,

即CPP代碼中15行的作用。

然后就可以盡情地玩耍了。

 

還有個問題,就是CWE是什么,其實CWE是一個索引ID,這個ID遵守一套XXXX的規則,

這個規則里面定義了若干種代碼可能出現的問題,通過這個ID,大家就可以統一使用並查詢出代碼出現了什么問題。

具體這個ID去哪查,就去下面的網站。

https://cwe.mitre.org/data/downloads.html

例子中的CWE是我隨便寫的,並不影響。

 

其實挺容易的,沒有那么難,只不過,任重而道遠啊。比如

下圖,指定位置有一個非常明顯的內存越界寫操作,可能會導致出現 0xC0000005,但是呢,cppcheck內置的模塊沒有發現這個問題,

這說明了一個事情,就是它內置模塊的檢測范圍可能還是以函數為單位的,只能檢測到當前函數內的事情,無法朔源檢測前面或者后面函數內的事情。

 

 

這只是一個點吧,我希望基於對它的學習,能多少再了解一些代碼審計相關的知識。

 

就到這吧

 

其實,由於它的模塊化是如此地出色,甚至可以插入一個python或者lua腳本解釋器之類的,讓它支持通過腳本來加模塊,那么應該會更完美。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM