在64位VS2012编译环境中导致此缓冲区溢出警告的原因是什么?

时间:2014-04-24 09:20:15

标签: c++ visual-studio-2012 c++11 64-bit

我有一个使用VS2010 64位环境编译的工作应用程序 - 在尝试将其迁移到VS2012编译器(C ++ 11)时,我收到C6386警告并且似乎无法找到根本原因:

这是产生警告的代码片段:

Packet::Packet(const Packet& oOther)
{
   m_vData.assign(oOther.m_vData.begin(),oOther.m_vData.end());
   if(NULL != oOther.m_pValueChecks)
   {
      m_pValueChecks = new set<string>*[oOther.m_vData.size()];
      for(size_t i = 0; i < oOther.m_vData.size(); ++i)
      {

        if(NULL == oOther.m_pValueChecks[i])
        {
             m_pValueChecks[i] = NULL;
        }
        else
        {
/// compiler warns on the below line
             m_pValueChecks[i] = new set<string>(oOther.m_pValueChecks[i]->begin(), oOther.m_pValueChecks[i]->end());
        }
      }
   }
}

包类定义:

class Packet
{
public:
    Packet();
    Packet(const Packet&);

    .....

    vector<pair<string,pair<FieldType,Field> > > m_vData;
    set<string> ** m_pValueChecks;
}

生成的警告:

c:\<my_path_and_file>(3331): warning C6386: Buffer overrun while writing to 'm_pValueChecks': the writable size is 'oOther.m_vData.public: unsigned __int64 __cdecl std::vector<struct std::pair<string,struct std::pair<enum Packet::FieldType,class Field> >,class std::allocator<struct std::pair<string,struct std::pair<enum Packet::FieldType,class Field> > > >::size(void)const ()*8' bytes, but '16' bytes might be written.: Lines: 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3322, 3323, 3325, 3331, 3323, 3325, 3331

由于编译环境为64位,oOther.m_vData.size()的类型为size_t,在64位环境中为64位无符号整数,因此for循环在范围内正确迭代,m_pValueChecks包含足够的已分配项目以满足分配。

为什么要生成警告?

2 个答案:

答案 0 :(得分:1)

您似乎在一些地方混合了other.m_pValueChecksother.m_vData。这可能会因阵列大小不匹配而导致内存损坏。

不要考虑这种可怕的双指针方法,而是考虑将你的设置放在另一个容器类型中,并让语言安全地为你完成所有这些。

答案 1 :(得分:0)

好的 - 继续深入研究场景 - 我发现该项目包含/ analyze开关,强制VS2012的Code Analysis选项始终运行。

删除此开关时,上面(讨厌的我同意)代码编译时没有任何警告。

现在,由于此特定代码在VS2010 64位环境中没有警告编译,因此VS2010与VS2012代码分析规则的差异是警告的主要嫌疑。

目前,我已经在我的迁移工作中通过了这个障碍,我将尝试继续理解规则之后的差异。如果有人可以对它进行遮挡,那么将它贴在这里会很棒。

修改 我发现Code Analyzer不能在VS2010上运行 - 编译器开关被忽略,这解释了为什么这个代码正在编译。无论如何都需要适当的重新考虑因素。

编辑2

人们经过深思熟虑(差不多6个月)后终于找到了根本原因......

m_pValueChecks = new set<string>*[oOther.m_vData.size()];
for(size_t i = 0; i < oOther.m_vData.size(); ++i)
{

  if(NULL == oOther.m_pValueChecks[i])
  {
       m_pValueChecks[i] = NULL;
  }
  else
  {
      /// commpiler warns on the below line
      m_pValueChecks[i] = new set<string>(oOther.m_pValueChecks[i]->begin(), oOther.m_pValueChecks[i]->end());
  }
}

原因是因为for循环使用i递增++i索引,这意味着首先i变量递增,然后被使用。

这意味着i变量可能会超过oOther.m_vData.size() m_pValueChecks已分配数组的大小。

for floop更改为for(size_t i = 0; i < oOther.m_vData.size(); i++)删除了警告。