错误:数组下标高于std :: vector :: insert的数组边界

时间:2016-08-03 16:45:02

标签: c++ visual-studio gcc visual-studio-2015

我正在使用-Werror进行编译,并发现警告已转换为错误:

1>  cc1plus.exe: warnings being treated as errors
1>  c:\rtems-4.9\bin\../lib/gcc/powerpc-rtems4.9/4.3.2/include/c++/bits/stl_vector.h: In function 'int someFunc()':
1>  D:\Git\Error_Parsing_script\Src\Plus\RTEMS_proj\c:\rtems-4.9\bin\..\lib\gcc\powerpc-rtems4.9\4.3.2\include\c++\bits\stl_vector.h(1043,1) : error: array subscript is above array bounds

从这段代码:

struct ControllerConfigDataType1 {
    char name[50];
    int controllerType;
};

int someFunc()
{
    std::vector<char> reply;
    reply.reserve(255);
    ControllerConfigDataType1 response = { { 0 } };
    reply.insert(reply.end(), reinterpret_cast<char*>(&response), reinterpret_cast<char*>(&response) + sizeof(response));
    return 0;
}

据我所知,this code is completely valid。一个特殊的事情是,如果我手动将sizeof(resonse)设置为&lt; = 50(char数组的大小),那么我们不会得到任何错误。似乎这个错误来自于尝试超出char name[50]response数组的范围,我认为我的指针取消引用reinterpret_cast<char*>(&response) + sizeof(response)是有意义的。

知道ControllerConfigDataType1的格式无法更改,有没有办法满足编译器对此行的预留?

请注意,这是来自RTEMS 4.9.2的稍微旧的编译器(请参阅下面的详细信息),这可能意味着此警告不会出现在更新版本的GCC中(并且不会出现在Visual C ++中VS2015)。

其他信息

错误提到了stl_vector.h(1043,1)函数的实现std::vector::insert

  // Called by the range insert to implement [23.1.1]/9
  template<typename _InputIterator>
    void
    _M_insert_dispatch(iterator __pos, _InputIterator __first,
           _InputIterator __last, __false_type)
    {
  typedef typename std::iterator_traits<_InputIterator>::
    iterator_category _IterCategory;
  _M_range_insert(__pos, __first, __last, _IterCategory());
}

从库中检索到的缩进

请注意,编译器由RTEMS 4.9.2提供,并具有以下版本信息:

Thread model: rtems
gcc version 4.3.2 (GCC)

1 个答案:

答案 0 :(得分:2)

获取对象字节的一种好方法是使用memcpy,并让字节类型为unsigned char。它很好,因为神圣标准至少有一个这样的例子,所以如果一个编译器扼杀了它,那么很容易说,嘿,这个编译器在标准的例子上扼杀,让&# 39;停止使用它。即使ISO标准中的例子是非规范性的。

您的原始示例,使用此方法:

int someFunc1()
{
    std::vector<unsigned char> reply;
    reply.reserve(255);     // Note: this, from original example, is only an optimization.
    ControllerConfigDataType1 response = { { 0 } };
//  reply.insert(reply.end(), reinterpret_cast<char*>(&response), reinterpret_cast<char*>(&response) + sizeof(response));
    int rs = reply.size(); int ds = sizeof(response); reply.resize(rs+ds); memcpy(&reply[rs], &response, ds);
    return 0;
}

此代码假定int足以满足此处使用的vector的大小,这对于网络数据包是合理的:它不能很好地为2 GB或更多。否则,将int替换为ptrdiff_t。可能重命名为Size

更一般地说,你可以抽象并集中它,这有助于测试和维护,如下所示:

#include <stddef.h>     // ptrdiff_t
#include <string.h>     // memcpy
#include <type_traits>  // std::is_trivially_copyable
#include <utility>      // std::enable_if_t

using Byte = unsigned char;
using Size = ptrdiff_t;

template< class Type
    // The following sanity-check line must be removed for a C++03 compiler:
    , class Enabled_ = std::enable_if_t< std::is_trivially_copyable< Type >::value >
    >
void append_to( std::vector<Byte>& v, Type const& o )
{
    Size const n_v_bytes = v.size();
    Size const n_o_bytes = sizeof( o );
    v.resize( n_v_bytes + n_o_bytes );
    memcpy( &v[n_v_bytes], &o, n_o_bytes );
}