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

Posted

技术标签:

【中文标题】错误:数组下标高于 std::vector::insert 的数组边界【英文标题】:error: array subscript is above array bounds for std::vector::insert 【发布时间】:2016-08-03 16:45:01 【问题描述】:

我正在使用-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) 设置为 response 中的char name[50] 数组的边界,我想从我的指针取消引用reinterpret_cast&lt;char*&gt;(&amp;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)

【问题讨论】:

每当我在代码审查中看到reinterpret_cast 时,我都会开始寻找错误(特别小心)(除了演员表本身)——通常会有一些.. 只是说。 "gcc 版本 4.3.2" - 这很。与您的问题完全无关,但您是否考虑过使用更现代的编译器(和 C++ 语言版本)? @JesperJuhl 1. 是的,但这是必要的,我们一直非常小心。 2.我们不能,它与操作系统相关,并且操作系统更新将是一个6个月 - 1年的项目,没有资源。 Downvoter,解释我可以改进什么的评论会很有帮助,这真的是一个糟糕的问题吗? 【参考方案1】:

获取对象字节的一个好方法是使用memcpy,并将字节类型设为unsigned char。这很好,因为神圣标准至少有一个例子,所以如果编译器阻塞它,那么很容易说,嘿,这个编译器阻塞了标准中的一个例子,让我们停止使用它。即使 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 );

【讨论】:

愚蠢的反对票,请解释你的愚蠢反对票。 这并不能回答问题,这就是投票失败的原因。问题是“为什么我有编译器警告”,你愚蠢的答案是“使用 memcpy”。 我们从 memcpy 转移到 std::vector 以使内存易于扩展,但我们并不想搬回去,但不是我的反对意见。 @Paul:你的意见没有回答这个问题。您能否详细说明一下,您认为它如何无法回答问题?我对你的想法很感兴趣(一般现象)。 @Ben:你可以使用memcpystd::vector,这不是问题。

以上是关于错误:数组下标高于 std::vector::insert 的数组边界的主要内容,如果未能解决你的问题,请参考以下文章

警告:数组下标高于数组边界 [-Warray-bounds]

指针与数组

指针和数组分析(下)

数组中的二分法查找

第29课 指针和数组分析(下)

keil5数组下标异常