VS2012静态分析:这个指针作为输出指针?

时间:2013-01-26 00:11:45

标签: visual-c++ visual-studio-2012 static-analysis

在此代码段中,Init()函数充当按需初始值设定项,用于填充结构的所有成员变量。这样做是为了避免调用默认构造函数堆栈中大型数组的所有成员:

struct Foo {
    int m_Member;
    void Init(int i);
};

void Foo::Init(int i) {
    m_Member = i;
    // Many other members initialized here.
}

void SomeFunction(int n) {
    Foo buffer[64];
    assert(n <= 64);
    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        buffer[i].Init(i * 3);
    }
    // Use buffer[0] - buffer[n-1] somehow.
}

这会在VS2012中使用/ analyze:

触发静态分析错误
warning C6001: Using uninitialized memory 'buffer'.: Lines: 17, 19, 20

我正在寻找一种方法来注释Foo :: Init(),以便不会发生此警告。还有很多其他方法可以消除警告,包括:

  • 添加空构造函数
  • 将Init()移动到构造函数并在循环中调用placement new

但我想避免改变代码的结构。

我尝试了以下注释但没有成功:

void _At_(this, _Out_) Init();

接受此语法,但仅将警告更改为:

warning C6001: Using uninitialized memory 'buffer'.: Lines: 18, 20, 21
warning C6001: Using uninitialized memory 'buffer[BYTE:0]'.: Lines: 18, 20, 21

有谁知道如何将此Init()函数的意图声明到静态分析引擎?

4 个答案:

答案 0 :(得分:0)

你的问题有点难以捉摸。您已SomeFunction显示int,但需要方法Init或构造函数的注释。

显示的警告绝对正确,assert不会隐藏警告。您需要if检查n是否比64更重要并重置n(或执行其他操作,但不能在n>=64时循环)。

对于注释,您需要使用__in_bcount或类似替代方案。一个例子:

bool SetBuffer(__in_bcount(8) const char* sBuffer);

有人说sBuffer是8 字节(不是元素)。

您可以阅读此this article以获取更多信息。

答案 1 :(得分:0)

添加额外的助手太难看了吗?

struct Foo {
    int m_Member;
    void Init(int i);
};

void Foo::Init(int i) {
    m_Member = i;
    // Many other members initialized here.
}

void Initialize(__in_bcount(sizeof(Foo) * n) Foo* buffer, int n) {
    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        buffer[i].Init(i * 3);
    }
}

void SomeFunction(int n) {
    Foo buffer[64];
    assert(n <= 64);
    Initialize(buffer, n);
    // Use buffer[0] - buffer[n-1] somehow.
}

答案 2 :(得分:0)

我通过实现索引数组的函数找到了解决方法。我将返回值标记为无效,以便此新函数仅在返回值仅用于初始化的特定情况下转义未初始化的值检查。我只在VS2017中测试了这个。

#define _Ret_invalid_                     _SAL2_Source_(_Ret_invalid_, (), _Ret1_impl_(__notvalid_impl))

template <typename T>
_Ret_invalid_ T& UninitialzedIndex(T* pt, int index)
{
   return pt[index];
}

然后,在索引值的地方,我调用UninitialzedIndex而不是operator []

void SomeFunction(int n) {
    Foo buffer[64];
    if (n <= 64)
      return;

    // Explicitly initialize what is needed.
    for (int i = 0; i < n; ++i) {
        UninitialzedIndex(buffer, i).Init(i * 3);
    }
    // Use buffer[0] - buffer[n-1] somehow.
}

答案 3 :(得分:-2)

只需添加一个默认构造函数(调用Init())。这有什么问题?

[编辑]根本问题不在于如何欺骗静态分析器或编译器。这是如何强制你不要让foo处于未初始化状态。添加默认构造函数没有任何问题。我想说不这样做的愿望会带来风险。

也许有些客户端会使用构造不良的foo类(在你写完之后很长时间你离开之后很久)也许他们会忘记调用.Init()??然后怎样呢?他们将留下未初始化的数据。

如果您希望执行该规则,那么任何静态分析都不会对您有所帮助。

在你戴上屋顶之前先照顾好基础。