1. 程式人生 > >【程式碼質量】C++程式碼質量掃描主流工具深度比較

【程式碼質量】C++程式碼質量掃描主流工具深度比較

本文由騰訊WeTest團隊提供,未經授權嚴禁轉載!更多資訊可直接戳連結檢視:http://wetest.qq.com/lab/ 
微訊號:TencentWeTest

文/張蓓

引言 
靜態程式碼分析是指無需執行被測程式碼,通過詞法分析、語法分析、控制流、資料流分析等技術對程式程式碼進行掃描,找出程式碼隱藏的錯誤和缺陷,如引數不匹配,有歧義的巢狀語句,錯誤的遞迴,非法計算,可能出現的空指標引用等等。統計證明,在整個軟體開發生命週期中,30% 至 70% 的程式碼邏輯設計和編碼缺陷是可以通過靜態程式碼分析來發現和修復的。

在C++專案開發過程中,因為其為編譯執行語言,語言規則要求較高,開發團隊往往要花費大量的時間和精力發現並修改程式碼缺陷。所以C++ 靜態程式碼分析工具能夠幫助開發人員快速、有效的定位程式碼缺陷並及時糾正這些問題,從而極大地提高軟體可靠性並節省開發成本。

靜態程式碼分析工具的優勢 :

1.自動執行靜態程式碼分析,快速定位程式碼隱藏錯誤和缺陷。

2. 幫助程式碼設計人員更專注於分析和解決程式碼設計缺陷。

3. 減少在程式碼人工檢查上花費的時間,提高軟體可靠性並節省開發成本。

2業界主流靜態程式碼掃描工具概況 
目前市場上的C++ 靜態程式碼分析工具種類繁多且各有千秋,本文將分別介紹TSC團隊自主研發的tscancode工具和當前4種主流C++靜態程式碼分析工具(cppcheck、coverity、clang、pclint),並從功能、效率、易用性等方面對它們進行分析和比較,以期幫助 C++開發人員更清晰靜態程式碼分析工具的工作效果、適用場景和擴充套件空間,同時在其對應專案特徵中選擇合適的工具應用到專案開發環節中。

以下為工具在付費價格、規則數量、準確率、掃描效率、編譯依賴、IDE支援、跨平臺支援、可擴充套件開發方面的對比資料。注:本次競品分析的選擇了3款遊戲專案(約500萬行程式碼)。 
圖片描述
圖片描述
在可擴充套件性上,TSC有專人維護,定期根據使用者需求擴充套件規則或新增功能特性,cppcheck和clang是開源工具,工具更新較慢,但如果使用者有特殊需求可以自己擴充套件開發,pclint和coverity是商業軟體,難以進行功能擴充套件。

同時,TSC有完整程式碼質量管理閉環平臺QOC支援; coverity和clang可用web端的結果展示,但無法自行管理問題流,需要進行二次開發; cppcheck和pclint缺少web端結果展示。

   以下重點比較具體檢查規則和有效問題報錯率。

3檢查規則大比拼 
3.1規則大類 
針對業內大量掃描工具在實際專案中掃描結果的影響比較,我們將程式碼質量問題分為以下幾大類:

① 致命類:可能導致程式宕機、無響應等影響範圍極大的錯誤;

② 邏輯類:可能造成程式不能達到預期邏輯結果的錯誤;

③ 編碼規範及其他類:可能造成程式的可讀性、可維護性較差的錯誤(不可達程式碼,無效的變數宣告等); 
圖片描述
3.2 規則大類分佈 
根據3大影響分類,其嚴重程度分別為高、中、低,各型別規則數量分佈為: 
圖片描述
從規則分類佔比來看:

① TSC針對網際網路產品高效開發修復原則,工具定位為針對致命和邏輯類問題,相對傳統、軍事、安全領域,並不關注編碼規範及編譯錯誤;

② coverity作為商業化軟體,在付費後新增規則上,達到覆蓋率最全面,除致命和邏輯類規則外,還有大量編碼規範、安全和針對其他語言(如java,C#)的規則;

③ cppcheck作為開源工具,應用範圍廣泛,根據開源社群場景蒐集,在各方面都有規則新增,但場景較為粗獷,場景雖多,但有效率不高。例如:cppcheck在初始化檢查上有5個子規則,樣本程式碼共掃描出312個問題,其中有效問題僅8個,有效率僅為3%。

④ pclint作為商業化軟體,在付費後新增規則上,達到覆蓋率最全面,除致命和邏輯類規則外,還有大量編碼規範、安全的規則;

⑤ clang作為開源軟體,規則較少,但規則型別分佈較為均勻,在致命、邏輯類,還有編碼規範、安全類都有規則新增。

3.3規則報錯數量 
整體規則數量上:pclint[915]>coverity[515]>cppcheck[245]>clang[74]>TSC[67]

可以看出pclint和coverity規則最多,TSC和clang規則最少,原因有如下3點:

① pclint和coverity作為商業化軟體,需求來源於傳統軟體、軍事、安全各個領域,其規則總數最多,其編碼規範類規則數量分別高達646條和382條;排除掉低價值的編碼規範類規則,規則數量排序為:pclint[269]>cppcheck[151]>coverity[133]>TSC[67]>clang[44]

② 在規則實際報錯數量上,以3款遊戲500萬行程式碼的結果覆蓋度來看; 
圖片描述
注:規則總數指工具所有的規則總數,報錯規則數指開啟工具所有規則情況下,掃描樣本程式碼所覆蓋的規則數量。

從實際專案掃描結果來看:

掃描出問題的規則數/規則總數:TSC[60%]>cppcheck[27%]>clang[19%]>coverity[10%]>pclint[9%]

pclint、coverity、cppcheck雖然規則數量很多,但因為其定製加入的大部分規則普遍適用度不高,大量規則可能在多個專案中都無法掃描出問題。有些規則卻在多個專案中掃描出大量非核心的問題,如:函式沒有被呼叫、未使用的變數、存在多餘的標頭檔案等。

③ 規則數量多來源於兩個方面,一方面是規則覆蓋更全面,另一方面是規則粒度劃分得更細;

通過對具體規則進行分析,發現在規則劃分粒度由細到出排序為[pclint,coverity,cppcheck,clang,TSC]

pclint和coverity劃分粒度最細,cppcheck,clang次之,TSC最粗。

例如:coverity的除0報錯分為整型除0,浮點數除0,取模除0;陣列下標越界也細分為訪問越界、讀越界、寫越界。Pclint和cppcheck初始化分為變數未初始化、結構體成員未初始化、類成員未初始化、string未初始化、data未初始化、union未初始化、全域性靜態變數未初始化等;而TSC則合併了一些過細的規則,未初始化上只分為變數未初始化和成員未初始化。

粒度劃分越細既有優點也有缺點:

優點:可以針對細分規則靈活配置開關,關掉準確率低的規則

缺點:規則數量太多, 使用者配置相當麻煩,新使用者很難理解多個相似的規則之前的區別。

TSC為降低使用者配置難度,在規則粒度劃分上相對粗獷,但會從中提取出其中準確率低的場景,作為單獨規則,從而達到可以關掉低準確率規則的目的。

4同類規則效果對比分析 
本文針對每個工具在關鍵報錯項,如:空指標、越界、變數未初始化、記憶體洩露、邏輯上的報錯結果進行分析。

樣本程式碼——3款遊戲專案(約500萬行程式碼)程式碼

測試物件——tscancode2.0、coverity7.5、cppcheck1.68、pclint9.0、clang3.4

有效報錯數——某類規則在3款遊戲專案的有效報錯數總和

準確率——某類規則在3款遊戲專案的平均準確率,準確率=有效報錯數/報錯總數*100%

綜合評分——綜合有效報錯數和準確率的評分,有效報錯數和準確率的權值暫定為45:55,綜合評分=有效報錯/最大有效報錯數*100*45%+準確率*100*55%

4.1空指標規則 
空指標檢查規則主要檢查是否存在對賦值為空的指標解引用的情況,空指標是c/c++中最大的問題,經常造成程式崩潰的致命錯誤。因此,C++靜態程式碼分析工具對空指標的檢查能力顯得尤為重要。

圖為五個工具對樣本程式碼掃描結果: 
圖片描述
圖片描述
從報錯數量和準確率來看:

有效報錯數:TSC [401] >coverity[219]>>clang[57] >cppcheck[20]>pclint[14]

準確率: coverity[95%]≈TSC[92%] ≈clang[90%]>>cppcheck[28%]>pclint[14%]

綜合評分: TSC[96分] >coverity[77分] >clang[56分]>cppcheck[18分]>pclint[8分]

1. 從準確率來看,在空指標檢查方面,不考慮掃描效率和掃描環境搭建複雜度,TSC、coverity和clang都很優秀,三者準確率都很高。cppcheck, pclint在結果準確率上和數量上都較差,不推薦使用。

2. 從空指標規則細分程度來看,TSC和coverity相當,細分場景挖掘更多,cppcheck規則並未細分空指標規則,從實際專案結果來看,只能檢查出dereferenceBeforeCheck場景的錯誤。Clang和pclint在空指標細分上維度跟TSC和coverity不同,比如:它們區分是引數指標解引用還是區域性變數解引用,細分粒度不夠且覆蓋場景較少,其覆蓋場景基本都被TSC和coverity包含。 
圖片描述
cppcheck掃描出來的問題存在大量誤報,誤報主要是冗餘的判空,並不會引起實際問題,具體誤報場景如下: 
圖片描述
3. 從有效報錯數量上,TSC有效報錯數量更多,細分場景挖掘更多,無疑是掃描空指標最佳選擇;clang覆蓋的場景較少,其有效報錯基本都能被coverity和TSC覆蓋,不過由於其準確率較高且免費,與TSC搭配使用也是不錯的選擇;而coverity雖然覆蓋場景多但因為只會報完全可信的問題,因此會漏掉部分有效報錯,例如:指標變數來源於函式返回值,而函式返回值是否為NULL依賴於使用者輸入,在靜態分析中coverity無法判斷其是否會為NULL,為保證準確率會漏掉該指標報錯。若專案對空指標漏報容忍度較高,且有足夠預算採購商業軟體,可以選擇coverity;而cppcheck和pclint檢查出的有效問題極少並伴隨大量誤報,同上結論,不宜使用。

4. 在易用性上,coverity和clang編譯環境構建複雜,編譯時長增加較多;TSC在易用性上也有一個缺點,即為提高準確率,在個別專案存在一次性配置工作。原因是個別項目存在自定義判空巨集,但由於不依賴編譯,TSC掃描的程式碼可能並不完整,導致個別自定義判空巨集找不到,需要在cfg.ini中配置自定義判空巨集。當然,如果掃描的程式碼完整度同編譯環境,則無此問題。

4.2越界規則 
越界一般來講是指陣列下標越界,或者緩衝區讀寫越界。這類錯誤會導致非法記憶體的訪問,引發程式崩潰或者錯誤。

下圖是五個工具對樣本程式碼掃描結果: 
圖片描述
圖片描述
注:越界對誤報判定的規則比較嚴格,即使場景識別本身無誤,但是通過程式碼邏輯可以推斷該場景不會越界的也判定為誤報。

例如: 
圖片描述
這裡由found變數間接推斷出data[region_index]不會越界,將其判定為誤報。

從報錯數量和準確率來看:

有效報錯數:coverity[98]>>TSC [18]>pclint[16] >cppcheck[6]> clang[4]

準確率: clang[100%] >coverity[80%]>TSC[70%] >cppcheck[67%]>>pclint[2%]

綜合評分:coverity[90分] >TSC[54分]≈clang[55分]>cppcheck[40分]>pclint[1分]

1. 在報錯數量上,coverity在越界檢查上有較大的優勢,因為coverity有較強的符號查詢和場景識別能力,能識別相對複雜的越界場景。其他四個工具同coverity相比還有差距,其中pclint存在大量誤報,表現最差。如:TSC和cppcheck只能識別陣列變數本身越界,但如果是一個指標p指向陣列的第一個元素,通過p[i]訪問時的越界,TSC和cppcheck都無法檢查,而coverity能找到p所指向的陣列定義,得到陣列大小,從而判斷p[i]是否越界。

2. clang越界這塊的準確率雖然最高為100%,但其覆蓋的場景單一(strncpy使用越界報了4條),其報錯都被TSC和coverity覆蓋,數量上和其他工具有較大差距。TSC越界檢查結果要略好於cppcheck,clang和pclint,TSC增加了對變數取值範圍的推斷,檢測出是否存在越界的風險。比如: 
圖片描述
(TSC越界有效報錯場景)

對於陣列下標iCountry的判定存在風險,程式碼執行到當前上下文時,iCountry可能取值為MAX_QT_COUNTRY_JIFEN_ITEM_CNT,而這正是陣列m_astDataInDB的長度,也就是說在這種邊界情況下會造成了陣列訪問越界。對於如上場景,應該將程式碼修改為iCountry>= MAX_QT_COUNTRY_JIFEN_ITEM_CNT。

4.3變數未初始化規則 
變數未初始化顧名思義:變數聲明後沒有賦初值,其分配的記憶體值是隨機的。這也是程式碼中容易出現的問題,會導致不確定的程式行為,造成嚴重的後果。

下圖是五個工具對樣本程式碼掃描結果: 
圖片描述
圖片描述
注:結果排除了3個工具都有的檢查項——建構函式中是否存在未初始化成員變數。在實際專案中發現,C++類建構函式中對成員變數不做初始化的情況是普遍的,很多程式碼會採用“延遲初始化”,即在實際用到該物件的時候呼叫類似Initialize的方法進行初始化。因此在此次對比中並沒有把這條規則納入進來。

從報錯數量和準確率來看:

有效報錯數:coverity[75]>>pclint[25] >TSC [9]>cppcheck[8]> clang[1]

準確率: TSC[75%] >coverity[68%]>pclint[26%] > clang[17%] >cppcheck[3%]

綜合評分:coverity[82分] > TSC[47分] >pclint[30分] > clang[10分] >cppcheck[6分]

1. 在報錯數量上,coverity初始化檢查場景覆蓋比其他四個工具要全,TSC為保持準確率,規則覆蓋上比較保守,而cppcheck存在比較嚴重的誤報問題,準確率僅為3%。pclint的誤報也相對很高,clang在初始化這塊顯得無能為力。從上圖可以很容易發現cppcheck的誤報數量相當得高,cppcheck會將如下的場景判定為未初始化: 
圖片描述
(cppcheck誤報場景)

SMD_POS是一個簡單的結構體,它包含了一個空的建構函式,cppcheck依據這點判定這是一個未初始化的錯誤。但這樣的場景不會有什麼問題,算是一個誤報。這導致了cppcheck在未初始化規則的結果可信度大大降低。

2. coverity在未初始化這塊的場景覆蓋比較全,特別是對結構體物件的欄位的初始化情況的檢測,因為其基於編譯可對變數做路徑跟蹤,例如:建構函式裡面呼叫了init()函式,coverity會繼續跟蹤init()函式中是否有對變數的賦值,所以掃描覆蓋場景最全。coverity的誤報主要分為兩類:一類是對幾種未初始化場景的識別上存在問題,如:,變數在某個分支的確沒有初始化,但用了一個狀態標識其未初始化,當使用這個變數前會使用狀態標記來判斷其是否沒有初始化,保證使用的變數都是初始化過了的。另一類就是上面提到的“低價值報錯”,即通過程式碼邏輯或者做了程式碼保護,保證變數不會因為沒有初始化而產生實際的問題。如:一個表示時間的結構體,裡面欄位有year,month,day,hour,min,day這個欄位沒有初始化,但實際程式碼中也沒有用到這個欄位,因此並不會產生任何問題。

TSC在未初始化變數的檢查因不具備路徑分析能力,而以分支作用域檢查特定變數在各個程式碼分支的初始化情況,誤報率保持在相對低的一個水平。但場景覆蓋較少,沒有針對結構體欄位的初始化場景做覆蓋。因為對結構欄位的初始化方式相對比較多樣:逐個欄位初始化,函式呼叫初始化,建構函式初始化等。

4.4記憶體/資源洩露規則 
記憶體洩漏指由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體,從而造成了記憶體浪費的情況。記憶體洩漏是靜態下很難檢測的一種錯誤,一般需要動態分析工具進行檢測,如valgrind工具會捕獲malloc()/free()/new/delete的呼叫,監控記憶體分配和釋放,從動態上檢測程式是否存在記憶體洩漏。因此,靜態程式碼分析能檢查的記憶體洩漏就非常有限了,當前各工具主要是從程式碼寫法上檢查記憶體分配和釋放是否配對使用。比如:fopen開啟檔案後在退出函式前是否有執行fclose,new[]和delete[]是否配對使用等。

下圖是五個工具對樣本程式碼掃描結果: 
圖片描述
圖片描述
注:以上資料排除了cppcheck35個低價值報錯,這裡排除的cppcheck35個報錯都是基本資料型別的new和delete不匹配(如char* p=new char[100];delete p;)雖然這種寫法不規範,但由於實際上不會造成記憶體洩漏,很多專案不會對此進行修復。

從報錯數量和準確率來看:

有效報錯數:pclint[55] >TSC[40]>coverity [29]>cppcheck[28]> clang[0]

準確率: coverity[100%]=cppcheck[100%] >TSC[73%]>pclint[23%] > clang[N/A]

綜合評分:coverity[79分] ≈ TSC [73分]≈cppcheck[77分]>pclint[57分]>clang[0分]

從報錯數量上看出,在記憶體洩漏檢查方面,pclint雖然發現有效問題最多,但誤報很高,不推薦使用。TSC的有效錯誤數比coverity和cppcheck多,但誤報也相對較高。clang則不具備洩露類場景的檢測能力。

注:由於靜態掃描能檢查的記憶體洩露場景都非常明確,因此一般都不會出現問題,TSC的15個誤報也非場景識別有誤而是工具底層bug導致,後續會對底層bug進行修復。如:#ifdef 和#else分支中各有一個fopen,實際編譯時只會走其中1個分支識別1次fopen,但由於底層bug識別了2次fopen,導致誤報。

4.5邏輯錯誤規則 
邏輯錯誤:指可能存在的邏輯問題,如if不同分支內容相同,在switch內缺少break等,對指標使用sizeof進行空間分配等問題。

下圖是五個工具對樣本程式碼掃描結果: 
圖片描述
圖片描述
注:這些報錯中剔除了一些無修改意義且結果數量很多規則:如:coverity掃描存在7484條Logically dead code(邏輯程式碼不可達)報錯。cppcheck存在2246條unusedFunction(函式未被使用)報錯。

從報錯數量和準確率來看

有效數量:TSC[293]>coverity[164]>clang[142] >cppcheck [120]>pclint[116]

準確率:clang[97%] >TSC[93%]>coverity(88%)>pclint[72%] >cppcheck[55%]

綜合評分:coverity[94分] > TSC[86分] > clang[80分] >cppcheck[63分] >pclint[27分]

從報錯數量和準確率上可以看出TSC可以更有效的發現邏輯類問題。但各工具邏輯類場景各有特色,互為互補,可以一同選擇掃描,但cppcheck和pclint準確率較低,可以較少選擇。clang的準確率最高,但clang掃描出來的邏輯錯誤中有一大半為低價值的邏輯錯誤,比如clang掃描出來的142條邏輯錯誤中就有140條“變數賦值但沒有使用”錯誤。

1. TSC,coverity具備較強巨集展開能力

以DuplicateExpression規則為例,TSC發現DuplicateExpression規則報錯32條, cppcheck發現DuplicateExpression規則報錯12條。因為TSC可以對巨集進行更有效展開,例如:

這種報錯TSC可以準確的識別出來,巨集MAX_TASK_TAB_SIZE和MAX_TASK_RES_NUM為相同的數值,而cppcheck無法區分發現這類問題,只能進行簡單的文字匹配。coverity在推斷能力上也不差,在這點也明顯優於cppcheck。

2. TSC規則型別更有效

經過篩選,TSC只保留價值更高的推斷和有效規則;

Ø 增加一些函式檢查規則,如:MemsetZeroBytes,這種錯誤的Memset寫法:memset(ctYear, sizeof(ctYear), 0);可疑的陣列下標使用等這些規則在coverity邏輯類檢查中並沒有體現,而coverity只會報出非常準確的報錯如:if分支完全相同等檢查項。

Ø 剔除價值低的無效規則,如coverity規則Logically dead code,指一些邏輯上不可達的廢棄程式碼;cppcheck規則memsetClassFloatc指對存在Float型別成員變數的Class使用Memset,當時程式碼中發現基本都是Memset為0,並不會有資料丟失等問題。故這類規則發現有效問題很低,在數量較大的情況下,需要耗費大量的人力來確認,價效比不高,TSC已經將這種規則剔除。

總的來說,TSC在發現問題和準確率方面表現都不錯,可以節省大量的人力在鎖定邏輯型別錯誤。

TSC在某些細小規則的推斷能力上比coverity要稍微弱一些,如規則Missing break in switch:coverity發現全部準確的報錯,TSC存在一定的誤報,這些複雜場景需要較強的動態計算如: 
圖片描述
5 常見誤報場景 
5.1 空指標常見誤報場景 
誤報場景一(cppcheck) 
圖片描述
以上538行程式碼報quiz_set_ptt存在空指標訪問。

誤報原因:538行只是指標的比較,並沒有解引用,這是一個比較低階的誤報。

誤報場景二(coverity) 
圖片描述
以上119行程式碼報actor存在空指標訪問,判定邏輯如下:112行對actor進行了判空,說明actor在當前上下文可能為空。所以119行actor可能為空。

誤報原因:xy_assert_retval是個巨集,展開後包含有return語句,即如果actor為空115行就返回了,119行actor不會為空。

5.2 越界常見誤報場景 
誤報場景一(TSC) 
圖片描述
以上83行程式碼報第陣列訪問可能越界,判定邏輯如下:第61行的if語句對req_list.num的取值範圍作了限制,req_list.num在當前上下文的最大值可以是MAX_RECRUIT_REQ_LIST_SIZE(4);83行req_list.陣列物件用req_list.num作為其陣列訪問的下標,當req_list.num取值為MAX_RECRUIT_REQ_LIST_SIZE時發生越界(req_list.陣列的長度為MAX_RECRUIT_REQ_LIST_SIZE(4))。

誤報原因:第79行的if條件保證了之後的程式碼req_list.num的值不會等於MAX_RECRUIT_REQ_LIST_SIZE,所以這是一個誤報。

誤報場景二(cppcheck) 
圖片描述
以上第691行程式碼報t_index_map可能取值-1越界,判定邏輯如下:665行宣告t_index_map並賦值為-1,t_index_map的賦值在681行,但681行在for迴圈裡面,而for迴圈存在不能進入的可能性,所以在691行使用t_index_map可能未初始化。

誤報原因:進入691行程式碼的前提條件是found變數為true,而found為true保證了t_index_map被賦值了。

誤報場景三(coverity) 
圖片描述
以上第146行程式碼報src_index + 1可能取值為4越界,判定邏輯如下:139行對src_idx的取值範圍進行了限定:0, 3,因此146行src_idx + 1可能為4導致對team_ptr->team_member訪問越界。

誤報原因:144行對src_idx的取值範圍進行了過濾,保證了src_idx+1不會越界。

5.3未初始化常見誤報場景 
誤報場景一(cppcheck) 
圖片描述
以上第462行程式碼報ret未初始化錯誤,判定邏輯如下:ret變數在第434行宣告,在switch中的兩個case中均有初始化程式碼,但是在default分支中沒有對ret進行初始化,因此判定462行可能會返回一個沒有初始化的ret。

誤報原因:default分支中的xy_assert_retval是一個巨集,因為cppcheck巨集查詢策略的原因導致該巨集沒有展開。實際上巨集展開包含了return語句,也就是說如果進入default分支就函式就直接返回而不會執行到462行程式碼。

誤報場景二(coverity) 
圖片描述
以上第284行程式碼報careers未初始化錯誤,判定邏輯如下:careers陣列在第278行宣告,但在for迴圈對每個陣列成員進行了初始化。這可能造成careers完全沒有初始化,或者只初始化了一部分。因此在284行使用careers存在未初始化錯誤。

誤報原因:通過程式碼邏輯可知,career_num代表的是careers被初始化的長度,在訪問careers陣列元素的時候,通過career_num進行了保護,因此不會出現未初始化的錯誤。

5.4洩露類常見誤報場景 
誤報場景一(TSC) 
圖片描述
以上第63行程式碼報fp存在資源洩露風險錯誤,判定邏輯如下:xy_assert_retnone巨集展開後,含有return語句,也就是說fp在呼叫fclose之前可能返回,存在洩露風險。

誤報原因:實際上程式碼邏輯決定了函式return的前提條件fp為空。這個時候是沒有必要呼叫fclose的,不存在洩露風險。

誤報場景二(pclint) 
圖片描述
以上第139行程式碼(~CGIProcessor(), 解構函式)報存在資源洩露風險錯誤,因為沒有釋放_cgiContainer。判定邏輯如下:_cgiContainer作為CGIProcessor的一個指標成員(第149行),需要在解構函式中進行釋放,否則為記憶體洩露。

誤報原因:CGIProcessor物件並不own _cgiContainer指向的物件,不需要它來釋放。

5.5邏輯類常見誤報場景 
誤報場景一(cppcheck) 
圖片描述
以上4596行程式碼報“對包含有float成員的物件呼叫memset方法”錯誤。

誤報原因:利用memset對一個物件的資料欄位清零是比較常見的做法,float成員清零後值也為0,不會造成什麼問題。

本文由騰訊WeTest團隊提供,未經授權嚴禁轉載!更多資訊可直接戳連結檢視:http://wetest.qq.com/lab/ 
微訊號:TencentWeTest