C++ 在PVS Studio中BOOST_REQUIRE之后将变量标记为非NULL
我正在使用PVS Studio分析我的测试代码。通常存在形式的构造C++ 在PVS Studio中BOOST_REQUIRE之后将变量标记为非NULL,c++,null-pointer,pvs-studio,boost.test,C++,Null Pointer,Pvs Studio,Boost.test,我正在使用PVS Studio分析我的测试代码。通常存在形式的构造 const noAnimal* animal = dynamic_cast<noAnimal*>(...); BOOST_REQUIRE(animal); BOOST_REQUIRE_EQUAL(animal->GetSpecies(), ...); const noAnimal*animal=dynamic_cast(…); 助推器(动物); 增强需要相等(动物->获取物种(),…); 但是,我仍然收到一
const noAnimal* animal = dynamic_cast<noAnimal*>(...);
BOOST_REQUIRE(animal);
BOOST_REQUIRE_EQUAL(animal->GetSpecies(), ...);
const noAnimal*animal=dynamic_cast(…);
助推器(动物);
增强需要相等(动物->获取物种(),…);
但是,我仍然收到一条警告,最后一行可能会取消对潜在空指针“animal”的引用
我知道可以将函数标记为“不返回NULL”,但也可以将函数标记为有效的NULL检查,或者让PVS Studio以其他方式意识到animal
在BOOST\u REQUIRE(animal)之后不能为NULL代码>
如果首先通过任何assert
flavor检查指针,也会发生这种情况。感谢您提供了一个有趣的示例。我们会想,我们可以用BOOST\u REQUIRE
宏做些什么
目前,我可以为您提供以下解决方案:
之后某处
#include <boost/test/included/unit_test.hpp>
这样,您将向分析器发出一个提示,假条件导致控制流中止。
这不是最漂亮的解决方案,但我认为它值得告诉你。用一个大的评论回应是一个坏主意,因此下面是我对以下主题的详细回应:
虽然这是可能的,但将该定义包含在
所有测试用例文件。此外,这不仅限于BOOST_所需,还包括
也适用于assert、SDL_assert或用户指定的任何其他自定义宏
可能需要
应该理解有三种类型的测试宏,每种类型都应该单独讨论
第一种类型的宏只是警告您调试版本出错。典型的例子是assert
宏。以下代码将导致PVS Studio analyzer生成警告:
T* p = dynamic_cast<T *>(x);
assert(p);
p->foo();
此代码不会触发警告
您可能会争辩说,您100%确信dynamic_cast
永远不会返回nullptr
。我不接受这个论点。如果您完全确定强制转换总是正确的,则应使用更快的静态\u强制转换
。如果不能确定,则必须在取消引用指针之前对其进行测试
好吧,我明白你的意思。您确信代码是正确的,但是您需要使用dynamic_cast进行检查,以防万一。好的,然后使用以下代码:
assert(dynamic_cast<T *>(x) != nullptr);
T* p = static_cast<T *>(x);
p->foo();
下面是测试宏的声明方式:
#define ENSURE(x) do { if (!x) Error("zzzz"); } while (0)
使用指针:
T* p = dynamic_cast<T *>(x);
ENSURE(p);
p->foo();
或:
这将有助于消除错误警告。因此,正如您所看到的,在大多数情况下,使用自己的宏修复问题非常容易
但是,如果处理来自第三方库的不小心实现的宏,可能会更棘手
这就引出了第三类宏。您无法更改它们,分析器也无法确定它们的具体工作方式。这是一种常见的情况,因为宏可能以非常奇特的方式实现
在这种情况下,您还有三个选择:
使用本发明中描述的假阳性抑制手段之一抑制警告李>
使用我在前面介绍的技术李>
给我们发电子邮件
我们正在逐渐增加对流行库中各种复杂宏的支持。事实上,分析器已经熟悉您可能遇到的大多数特定宏,但程序员的想象力是无穷的,我们无法预见每一个可能的实现。谢谢您的回复。尽管这是可能的,但是在所有的测试用例文件中包含这个定义将是一件痛苦的事情。此外,这不仅限于BOOST\u REQUIRE
,还适用于assert
、SDL\u assert
或用户可能使用的任何其他自定义宏。因此,我看到了两种解决方案:要么让用户指定一个“assert”(宏名称)列表,然后假设条件为true(因为这是assert的原因)。要么至少有一个全局的、只有PVS的文件,其中的定义由PVS读取并假设为使用(类似于cpp.hint
)。所以你可以把这样的定义放在一个中心位置。然而,我认为这将是困难的,因为定义可能会在任何文件包括。我不同意你的动态_演员故事。首先,有时您需要动态转换(多重继承…),但请确保它不会失败(例如,虚拟函数返回类型)。或者第二,您断言它是有效的,但仍然保持动态_强制转换,以便在发布模式下获得空指针异常,而不是UD。在我看来,这比对(应该是)不可能的情况进行额外的检查和抛出要好。(例如,一个函数返回了该类型,因此它应该是可转换的,但您希望防止该函数中出现C&P错误。棘手的宏:这就是我建议配置选项的原因
void Error(const char *message);
#define ENSURE(x) do { if (!x) Error("zzzz"); } while (0)
T* p = dynamic_cast<T *>(x);
ENSURE(p);
p->foo();
[[noreturn]] void Error(const char *message);
__declspec(noreturn) void Error(const char *message);