2017-08-28 74 views
0

我在我的項目Torrent File Editor中使用了PVS-Studio。有一個誤報。 Here沒有真正的問題,但我得到這樣的錯誤:錯誤肯定V595'_parent'指針在利用nullptr進行驗證之前被利用了

torrent-file-editor/abstracttreenode.h:138: error: V595 The '_parent' pointer was utilized before it was verified against nullptr. Check lines: 138, 139.

代碼片段:

inline T *sibling(int row) const 
{ 
    Q_ASSERT(_parent); 
    Q_ASSERT(row < _parent->childCount()); // -V595 PVS-Studio 
    return _parent ? _parent->child(row) : nullptr; 
} 

這裏Q_ASSERT僅調試版本檢查。發佈版本中不會執行這種檢查。對於版本我使用_parent ? ... : ...來防止可能的崩潰。因此,在Debug版本中重複檢查完全可以。

我通過特別評論抑制了這種誤報。所以這不是問題,但認爲PVS-Studio應該處理這種情況。

+0

它是否與assert()一起工作?我記得LLVM的靜態分析器也與Q_ASSERT –

+0

混淆assert()相同。 –

+0

如果:'return _parent!= nullptr? _parent-> child(row):nullptr;'? – AlexanderVX

回答

1

V595診斷邏輯很簡單。如果在開始時解除引用指針,則會發出警告,然後驗證其是否等於nullptr。

當然,有很多情況下分析儀會很安靜,遇到了這樣的模式。包括指針不等於nullptr時的情況,因此分析器將保持安靜。然而,Q_ASSERT(_parent)不保證指針_parent非零。如果_parent爲零,則Q_ASSERT語句將使用qFatal函數輸出以下消息。如果您使用默認消息處理程序,則此函數將中止以創建核心轉儲。

您可以安裝您自己的處理程序,它將繼續運行該程序。所以理論上分析儀是正確的。可能會發生空指針的潛在取消引用。

我們不是理論家,而是實踐,我們認識到這段代碼應該被認爲是正確的。分析儀不熟悉此類代碼視圖,其中尚未使用宏Q_ASSERT。我們將修改分析器,以便它開始將這些代碼模式視爲正確。即在未來的分析會認爲這裏:永遠不會執行

Q_ASSERT(_parent); 
Q_ASSERT(row < _parent->childCount()); 

_parent->childCount()函數調用,如果指針_parent等於nullptr。如果指針爲空,則由於調用qFatal(),程序將提前停止工作。

當然,正如我上面已經說過的,您可以更改處理程序的行爲,並且不會導致中止程序。但是,在實踐中,沒有人會改變處理程序並編寫我們在此考慮的代碼。

這可能是答案的終點。所以,我們會改進分析儀,就是這樣。但是,不可能預見所有可能的選擇。如果是我們自己的宏,如何抑制一個警告?

假設這個自制錯誤記錄系統和分析儀對自定義函數Foo()一無所知。

void Foo(bool expr); 
#define Q_ASSERT(expr) Foo(expr); 

inline T *sibling(int row) const 
{ 
    Q_ASSERT(_parent); 
    Q_ASSERT(row < _parent->childCount()) 
    return _parent ? _parent->child(row) : nullptr; 
} 

最簡單的,但不是最好的辦法就是明確標示警告爲假時使用註釋:

Q_ASSERT(row < _parent->childCount()) //-V595 

另一種選擇是改變編寫代碼的風格,寫如下:

inline T *sibling(int row) const 
{ 
    if (_parent == nullptr) 
    { 
    Q_ASSERT(false); 
    return nullptr; 
    } 
    Q_ASSERT(row < _parent->childCount()); 
    return _parent->child(row); 
} 

對於這樣的代碼,分析儀不會發出警告V595,因爲沒有理由這樣做。代碼變得更長一點,但在我看來,它現在更符合邏輯正確和安全。我推薦這種處理這種警告的方式。

最後是在宏中使用警告抑制機制。要在宏定義的頭文件中執行此操作,您應該寫一條註釋:

//-V:Q_ASSERT:595 

此警告消失後。當然,並不總是可以更改聲明宏的文件。然後,您可以使用其中一個全局文件。在Visual C++項目中,一個好的候選項是stdafx.h。另一種選擇是使用診斷配置文件(pvsconfig)。所有這些方法在「Suppression of false alarms」部分的文檔中有詳細描述。 markup base也存在。