上次我用新的GCC12编译了我的项目,它给了我关于坏内存缓冲区大小的警告。以前版本的GCC没有报告这样的警告。
这个简单的代码示例展示了我的情况:
#include <vector>
#include <cstdint>
#include <iostream>
struct [[gnu::packed]] S {
uint32_t a;
uint8_t b;
uint16_t c;
};
std::vector<uint8_t> s_to_bytes(const S &s) {
S x = s;
std::vector<uint8_t> res;
res.insert
( res.begin()
, reinterpret_cast<uint8_t*>(&x)
, reinterpret_cast<uint8_t*>(&x) + sizeof(S)
);
return res;
}
int main () {
S s{1,2,3};
auto bytes = s_to_bytes(s);
for (auto &x : bytes) std::cout << static_cast<int>(x) << " ";
std::cout << std::endl;
return 0;
}
当我用g++ 12通过命令
编译这段代码时g++ -Wall -Wextra -O2 -Wpedantic -std=c++20 invalid_optimization.cpp
打印警告:
inlined from ‘std::vector<unsigned char> s_to_bytes(const S&)’ at invalid_optimization.cpp:16:5:
/usr/include/c++/12/bits/stl_algobase.h:431:30: warning: ‘void* __builtin_memmove(void*, const void*, long unsigned int)’ writing 1 or more bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
431 | __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In member function ‘_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = unsigned char]’,
inlined from ‘constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = unsigned char]’ at /usr/include/c++/12/bits/allocator.h:183:40,
inlined from ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up> >::allocate(allocator_type&, size_type) [with _Tp = unsigned char]’ at /usr/include/c++/12/bits/alloc_traits.h:464:28,
inlined from ‘constexpr std::_Vector_base<_Tp, _Alloc>::pointer std::_Vector_base<_Tp, _Alloc>::_M_allocate(std::size_t) [with _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]’ at /usr/include/c++/12/bits/stl_vector.h:378:33,
inlined from ‘constexpr std::_Vector_base<_Tp, _Alloc>::pointer std::_Vector_base<_Tp, _Alloc>::_M_allocate(std::size_t) [with _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]’ at /usr/include/c++/12/bits/stl_vector.h:375:7,
inlined from ‘constexpr void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = unsigned char*; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]’ at /usr/include/c++/12/bits/vector.tcc:787:40,
inlined from ‘constexpr void std::vector<_Tp, _Alloc>::_M_insert_dispatch(iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = unsigned char*; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]’ at /usr/include/c++/12/bits/stl_vector.h:1779:19,
inlined from ‘constexpr std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = unsigned char*; <template-parameter-2-2> = void; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]’ at /usr/include/c++/12/bits/stl_vector.h:1481:22,
inlined from ‘std::vector<unsigned char> s_to_bytes(const S&)’ at invalid_optimization.cpp:16:5:
/usr/include/c++/12/bits/new_allocator.h:137:55: note: at offset 7 into destination object of size 7 allocated by ‘operator new’
137 | return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
此警告表明insert
进入向量被优化为__builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
调用,但大小无效。vectorinsert
文档告诉我们插入是在[first, last)
范围内执行的,所以结构指针的末尾必须指向结构之后的下一个字节,就像迭代器.end()
一样,但是GCC优化使这个有效代码无效的memmove调用,它可能得到结构大小+ 1而不仅仅是结构大小。看起来__builtin_memmove
只是first
和last
指针的差异,而不是last - first - 1
。
我的问题是:我的vector::insert
使用无效或它是GCC12优化错误?
我的问题是:我的
vector::insert
使用无效还是它是GCC12优化错误?
这是gcc中的一个警告错误,在注释中提到过。减少
#include <vector>
#include <array>
std::vector<int> s_to_bytes() {
std::vector<int> res;
std::array<int, 4> s{};
res.insert(res.begin(), s.begin(), s.end());
return res;
}
上面的代码无疑是格式良好的,但gcc-12意外溢出警告__builtin_memmove
。
Bug归档106199.