_Pre_defensive_注释如何工作?

时间:2014-06-04 18:56:28

标签: visual-c++ visual-studio-2012 sal

所以我很熟悉使用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)注释,但我不明白如何使用它。

感谢。

1 个答案:

答案 0 :(得分:1)

AFAICT在添加_defensive_注释时,目前没有(公共)差异。但是,微软有额外的&他们在内部使用的扩展分析仪。这些可能会使用注释,也可能在将来向公众发布。

所以这是一个权衡。如果你认为它们过多地混淆了声明,那么删除声明并没有什么坏处(尽管请注意,通过_Use_decl_annotations_你只需要将标注放在标题中)。另一方面,将来可以使用它,也可以用作预期用途的文档。

编辑:对于_In_defensive_(annotes),它允许您将_Pre_defensive_注释应用于所有注释(在annotes中给出)。此外,这允许您将注释放在不同的位置,即

_In_defensive(_Pre_satisfies_(pInt != nullptr))
void fun3(int* pInt)
{
}