程序人生:讀開源項目需謹慎!盤點C++開源項目中的十大BUG

又一年即將結束,是時候盤點一下開源項目中的 Bug 了。2020 年的盤點可能還須要點時間,本文咱們先來看看 2019 年開源 C/C++ 項目中遇到的一些最有趣的槽點。html

 

No. 10. 咱們正運行在什麼操做系統上?

V1040 可能拼寫錯誤預約義宏名稱。’MINGW32_‘有點兒像’MINGW32__’。winapi.h 4112程序員

 

MINGW32_ 宏的名稱拼寫有誤(MINGW32 實際上被聲明爲MINGW32__)。在項目的其它地方,拼寫是正確的:編程

 

順便說一句,這個 bug 並非在文章"CMake: the Case when the Project’s Quality is Unforgivable"中首次被描述,而是在一個開源項目的 V1040 診斷中就真正被第一次發現的 bug(2019 年 8 月 19 日)。json

https://www.viva64.com/en/b/0658/?ref=hackernoon.comapi

 

No. 9. 哪一個先?

V502 可能’?:‘運算符的工做方式與預期不符。’?:‘運算符的優先級比’=='運算符低。mir_parser.cpp 884數組

 

咱們感興趣的下面的部分:安全

 

'=='運算符的優先級比三元運算符 (?:) 高。所以,這個條件表達式的求值順序錯誤,等效於以下代碼:微信

 

因爲常量 OP_intrinsiccall 和 OP_intrinsiccallassigned 都是非 null 的,這個條件會一直返回 true,這意味着 else 分支是沒法訪問的代碼。函數

這個 bug 在文章"Checking the Ark Compiler Recently Made Open-Source by Huawei"中被提到。學習

https://www.viva64.com/en/b/0690/?ref=hackernoon.com

 

No. 8. 危險的位運算符

V1046 在位運算符’&='中不安全地使用’bool’和’int’類型。GSLMultiRootFinder.h 175

 

代碼建議 SetFunctionList 函數遍歷一個迭代器列表。若是至少有一個迭代器是無效的,這個函數會返回 false,不然就返回 true。

然而,SetFunctionList 函數對於有效的迭代器也會返回 false。讓咱們來看看是爲何。AddFunction 函數返回 fFunctions 列表中有效迭代器的數目。也就是說,添加非空迭代器將致使列表的大小遞增:一、二、三、4,以此類推。這就是 bug 生效的地方:

ret &= AddFunction(*f);

因爲這個函數返回一個 int 類型的值而不是 bool 類型,所以對於偶數值’&='運算符也會返回 false,由於偶數的最低有效位始終設置爲 0。這就是爲何一個微小的 bug 會打破 SetFunctionsList 的返回值,即便它的參數是有效的。

若是你仔細閱讀了代碼片斷(你是認真的,對吧?),你可能已經發現,它來自 ROOT 項目。是的,咱們也發現了這個 bug:「Analyzing the Code of ROOT, Scientific Data Analysis Framework」。

https://www.viva64.com/en/b/0682/?ref=hackernoon.com

 

No. 7. 變量混淆

V1001[CWE-563] 'Mode’變量被賦值了,可是直到函數結束都沒有被使用。SIModeRegister.cpp 48

 

對函數參數和類成員使用相同的名字是很是危險的,由於你極可能把它們混淆。而這裏就是這樣的。下面的表達式沒有意義:

Mode&= Mask;

函數的參數變化以後,這個參數以後不會以任何形式被使用。編程人員極可能想要寫的是:

 

這個 bug 在 LLVM 發現。咱們有一個傳統,不時地檢查這個項目。今年咱們又 檢查了一次這個項目。

 

No. 6. C++ 有本身的的規則

這個 bug 源於 C++ 規則並不老是遵循數學規則或「常識」。看看下面的代碼片斷,試着本身找出 bug 吧。

V709 發現的可疑比較:‘f0 == f1 == m_fractureBodies.size()’。記住, ‘a == b == c’並不等價於’a == b && b == c’。

 

這個條件表達式彷佛是在檢查 f0 等於 f1,而且等於 m_fractureBodies 中元素的數目。這可能意味着,檢查 f0 和 f1 是否位於 m_fractureBodies 數組的末尾,由於它們都包含被 findLinearSearch() 方法發現的一個對象。但實際上,這個條件表達式檢查 f0 是否等於 f1,而後檢查 m_fractureBodies.size() 是否等於 f0 == f1 表達式的結果。也就是說,這裏第三個運算數是 0 或 1。

這是一個好 bug!並且,幸運的是,這個 bug 很是罕見。到目前爲止,咱們只在 3 個開源項目中看到過這個 bug,並且有趣的是,這 3 個項目都是遊戲引擎。這不是 Bullet 中發現的惟一 bug;最有趣的一些 bug 在文章"PVS-Studio Looked into the Red Dead Redemption’s Bullet Engine"有描述。

https://www.viva64.com/en/b/0647/?ref=hackernoon.com

 

No. 5. 行末尾是什麼?

這個 bug 很容易發現,若是你知道其中細節的話。

V739 EOF 不該該與一個’char’類型的值進行比較。'ch’應該是’int’類型。json.cpp 762

 

這是你很難發現的一些 bugs 之一,若是你不知道 EOF 是被定義爲 -1 的話。所以,若是你試圖將它與一個帶標誌的字符類型變量比較時,條件表達式的結果幾乎總會是 false。惟一的例外是編碼爲 0xFF(255) 的字符。當與 EOF 比較時,這個字符會變成 -1,所以會讓這個條件表達式的結果爲 true。

在這幾年的衆多 bugs 中,前 10 名都是在計算機遊戲軟件中發現的:引擎或開源遊戲。你可能已經猜到了,這個 bug 也是來自遊戲領域。更多錯誤在"Cataclysm Dark Days Ahead: Static Analysis and Roguelike Games"一文中有描述。

https://www.viva64.com/en/b/0628/?ref=hackernoon.com

 

No. 4. 常量 Pi

V624 對於’3.141592538’常量可能有錯誤打印。考慮使用 <math.h> 中的 M_PI 常量。PhysicsClientC_API.cpp 4109

 

在 Pi 數字 (3,141592653…) 中有一個微小的打印錯誤:第 7 個小數位的數字「6」丟失了。

 

一個不正確的百萬分之一的小數位很難形成任何明顯的損害,可是最好使用庫裏已有的常量,其正確性有所保障。例如,Pi 數字由頭文件 math.h 中的 M_PI 常量表示。

你可能在文章"PVS-Studio Looked into the Red Dead Redemption’s Bullet Engine"中已經讀到過這個 bug,它在其中排第 6 位。若是你還沒讀到過,此次可別錯過。

https://www.viva64.com/en/b/0647/?ref=hackernoon.com

 

No. 3. 難以捉摸的異常

V702std::exception(以及相似的)中的類應該是’public’的(沒有指定關鍵字的話,編譯器默認是’private’的)。CalcManager CalcException.h 4

 

分析器檢測到來自 std::exception 的一個類使用了 private 修飾符(若是沒有指定的話默認使用 private)。這段代碼的問題是,試圖捕獲一個通用的 std::exception 將會致使這個程序錯過 CalcException 類型的異常。這個行爲源於 private 繼承禁止隱式類型轉換。

你確定不但願看到你的程序由於一個漏掉的 public 修飾符而崩潰。順便說一句,我打賭你在一輩子中確定至少用過這個應用程序一次,由於它就是老的 Windows Calculator,咱們早幾年也檢查過這個應用程序。

 

No. 2. 未閉合的 HTML 標籤

V735 多是一個不正確的 HTML。碰到"「閉合標籤時,預期的是」" 標籤。book.cpp 127

 

因爲它常常發生,C/C++ 源代碼自己沒有太多說明,所以讓咱們看看上面的代碼片斷生成的預處理代碼:

 

分析器發現了一個未閉合的 div 標籤。這裏有不少 html 代碼片斷,所以做者須要修改代碼。

很驚訝咱們能診斷出這種類型的 bugs 嗎?我第一次看到這一點時,印象也很是深入。所以,是的,咱們確實知道一些關於分析 html 代碼的知識。不過,只在 C++ 代碼中才行。:)

不只這個 bug 被排在第二位,這也是咱們的前 10 榜單中的第二個計算器。能夠閱讀"Following in the Footsteps of Calculators: SpeedCrunch"這篇文章,來看看咱們在這個項目發現的其它 bugs。

https://www.viva64.com/en/b/0618/?ref=hackernoon.com

 

No. 1. 難以捉摸的標準函數

這個 bug 位於第一位,是一種很是奇怪的 bug,可以成功經過代碼評審。

你本身試試發現這個 bug:

 

如今讓咱們看看分析器怎麼說:

V560 部分條件表達式老是 true:(’\n’ != c)。params.c 136.

很奇怪,對不對?讓咱們看看在另外一個文件(charset.h)中其它奇怪的點:

 

嗯,這確實很奇怪… 所以,若是變量 c 等於’\n’,那麼看起來無害的函數 isspace© 會返回 false,從而由於短路邏輯而不執行第二部分的檢查。並且若是 isspace© 執行,變量 c 將會等於 ‘’ 或’\t’,明顯不會等於’\n’。

你可能會說,這個宏與 #define true false 相似,像這樣的代碼永遠不能經過一個代碼評審。可是這個特殊的代碼片斷確實經過了代碼評審——並且還在代碼庫中等待被發現。

有關這個 bug 的更詳細的評論,請查看文章"Wanna Play a Detective? Find the Bug in a Function from Midnight Commander"。

https://www.viva64.com/en/b/0610/

 

結 論

 

咱們發現的這些 Bug 都是一些常見的複製 - 粘貼錯誤、不許確的常量、未閉合的標籤以及許多其它缺陷。可是咱們的分析器正在不斷演進和 學習 來診斷愈來愈多類型的問題,所以咱們確定不會放慢腳步,而且會像之前同樣按期發佈關於項目中發現的 bugs 的新文章。

做者介紹:

PVS-Studio 致力於尋找 C、C++、C#、Java 在 Windows、Linux 和 macOS 上的 bugs。

另外本人是一名CC++的程序員,若是你想更好的提高你的編程能力,好好學習C/C++編程知識的話!那麼你很幸運~

分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)

歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比本身琢磨更快哦!

另外本人是一名CC++的程序員,若是你想更好的提高你的編程能力,好好學習C/C++編程知識的話!那麼你很幸運~

C語言C++編程學習交流圈子,QQ羣1030652847點擊進入】微信公衆號:C語言編程學習基地

編程學習書籍:

 

編程學習視頻:

相關文章
相關標籤/搜索