2017-08-28 70 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也存在。