我将PVS-Studio用于我的项目Torrent File Editor。有一个误报。 Here没有真正的问题,但我收到了这样的错误:
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只是Debug版本检查。在Release版本中不执行此类检查。对于Release,我使用_parent ? ... : ...
来防止可能的崩溃。因此,在Debug版本中检查重复是完全可以的。
我通过特别评论来抑制这种误报。所以这不是问题,但认为PVS-Studio应该处理这种情况。
答案 0 :(得分:1)
V595诊断逻辑很简单。如果在开始时指针被解除引用,则会发出警告,然后验证是否与nullptr相等。
当然,在满足这种模式的情况下,分析仪会很安静。包括指针不等于nullptr的情况,因此分析仪将保持安静。
但是,Q_ASSERT(_parent)
并不能保证指针_parent
非零。如果_parent
为零,Q_ASSERT语句将使用qFatal函数输出以下消息。如果您使用的是默认消息处理程序,则此函数将中止以创建核心转储。
您可以安装自己的处理程序,它将继续运行该程序。理论上分析仪是正确的。可能会发生空指针的潜在解引用。
我们不是理论家,而是实践,我们意识到这个代码应该被认为是正确的。分析器不熟悉使用宏Q_ASSERT
的代码视图。我们将修改分析器,以便它开始将这些代码模式视为正确。即在未来的分析器将假设在这里:
Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount());
如果指针_parent->childCount()
等于nullptr,则永远不执行 _parent
函数调用。如果指针为null,则程序将因为调用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;
}
最简单但不是最好的方法是明确标记警告,因为false使用注释:
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也存在。