所以我相当熟悉使用 Microsoft Source Annotation Language(VS 2012-2013 风格)来描述带有指针的函数契约。
不过,我很好奇的一件事是,对于带_In_ _Pre_defensive_
注释的被调用者没有首先检查指针的情况,我希望得到与没有它不同的结果。[我们的许多遗留函数都希望这些参数的输入有效,但政策是要仔细检查。] 描述标记为防御而不是自我防御的函数是否存在静态分析错误?
从文档中,
如果函数出现在信任边界,我们建议您使用 _Pre_defensive_ 注释。"defensive" 修饰符修改了某些注解,表明在调用点,接口应该被严格检查,但是在实现主体中它应该假设可能传递了不正确的参数。在这种情况下,在信任边界处首选 In_Pre_defensive_,以指示尽管调用者在尝试传递 NULL 时会收到错误,但函数体将被分析为参数可能为 NULL,并且任何取消引用的尝试未先检查其是否为 NULL 的指针将被标记。
这是一个用于代码分析的小演示程序。我的所有 4 个函数都在静态分析中显示 C6387,但我希望看到一个额外的迹象,表明我的“防御”函数实际上并没有像fun0()
. 添加此限定符有什么好处吗?它确实使声明变得混乱,所以如果它没有帮助,很难证明把它放在那里是合理的。
// SAL2013.cpp : Defines the entry point for the console application.
#include "stdafx.h"
// pre-defensive annotation, but no check
void fun0(_In_ _Pre_defensive_ int* pInt)
{
auto oops = *pInt;
}
// not defensive, no check
void fun1(_In_ int* pInt)
{
auto oops = *pInt;
}
// defensive check, but not annotated defensively
void fun2(_In_ int* pInt)
{
if (pInt != nullptr)
{
auto oops = *pInt;
}
}
// defensive, with annotation
void fun3(_In_ _Pre_defensive_ int* pInt)
{
if (pInt != nullptr)
{
auto oops = *pInt;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int* p = nullptr;
fun0(p); // C6387 Invalid Parameter Value
fun1(p); // C6387 Invalid Parameter Value
fun2(p); // C6387 Invalid Parameter Value
fun3(p); // C6387 Invalid Parameter Value
return 0;
}
奖励问题:我在 sal.h 中也看到了一个_In_defensive_(annotes)
注释,但我不明白如何使用它。
谢谢。