所以我很熟悉使用Microsoft Source Annotation Language(VS 2012-2013风格)来描述带指针的函数契约。
我感到好奇的一件事是,我希望得到与_In_ _Pre_defensive_
不同的结果,而不是在没有它的情况下,注释被调用者不首先检查指针。 [我们的许多遗留函数都期望这些参数的有效输入,但是策略是要仔细检查。]是否存在静态分析错误来描述标记为防御的功能而不是自我保护?
来自docs,
如果函数出现在信任边界,我们建议您使用_Pre_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)
注释,但我不明白如何使用它。
感谢。
答案 0 :(得分:1)
AFAICT在添加_defensive_
注释时,目前没有(公共)差异。但是,微软有额外的&他们在内部使用的扩展分析仪。这些可能会使用注释,也可能在将来向公众发布。
所以这是一个权衡。如果你认为它们过多地混淆了声明,那么删除声明并没有什么坏处(尽管请注意,通过_Use_decl_annotations_
你只需要将标注放在标题中)。另一方面,将来可以使用它,也可以用作预期用途的文档。
编辑:对于_In_defensive_(annotes)
,它允许您将_Pre_defensive_
注释应用于所有注释(在annotes
中给出)。此外,这允许您将注释放在不同的位置,即
_In_defensive(_Pre_satisfies_(pInt != nullptr))
void fun3(int* pInt)
{
}