g++ 10.3.0:误报还是实际问题?
g++ 10.3.0: False positive or an actual problem?
使用 g++ 10.3 编译以下代码会给出一些可怕的警告(参见 https://godbolt.org/z/excrEzjsd):
#include <iostream>
#include <memory>
#include <vector>
#include <cstring>
#include <boost/algorithm/clamp.hpp>
namespace demo {
template <typename T, size_t N> constexpr std::size_t array_size(T (&)[N]) { return N; }
template <std::size_t N> inline void StrCpy(std::string::value_type (&dest)[N], const std::string::value_type *src) {
std::strncpy(dest, src, N);
dest[N - 1] = 0; // make sure the terminating NUL is there
}
template <std::size_t N> inline void StrCpy(std::string::value_type (&dest)[N], const std::string &src) { StrCpy(dest, src.c_str()); }
} // namespace demo
int main() {
struct a {
int m_num_lines;
char m_lines[6][201];
};
std::vector<std::string> lines{
"Line0",
"Line1",
"Line2",
"Line3",
"Line4",
"Line5",
"Line6",
"Line7",
"Line8",
"Line9",
"Line10",
};
auto theA = std::make_shared<a>();
theA->m_num_lines = boost::algorithm::clamp(lines.size(), 0, demo::array_size(theA->m_lines));
for (auto i = 0; i < theA->m_num_lines; i++) {
demo::StrCpy(theA->m_lines[i], lines[i]);
}
for (auto i = 0; i < theA->m_num_lines; i++) {
std::cout << theA->m_lines[i] << std::endl;
}
}
我不明白编译器实际上想说什么。我有错误还是编译器看到了幻影?顺便说一句:clang++ 和 MSVC 看不出这里有什么问题。
输出:
g++ -Wall -pedantic -O3 gcc.cpp -o gcc-bug
In file included from /usr/include/string.h:495,
from /usr/include/c++/10/cstring:42,
from gcc.cpp:4:
In function ‘char* strncpy(char*, const char*, size_t)’,
inlined from ‘void demo::StrCpy(std::__cxx11::basic_string<char>::value_type (&)[N], const value_type*) [with long unsigned int N = 201]’ at gcc.cpp:10:17,
inlined from ‘int main()’ at gcc.cpp:14:113:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:34: warning: ‘char* __builtin_strncpy(char*, const char*, long unsigned int)’ forming offset [1212, 1410] is out of the bounds [0, 1212] [-Warray-bounds]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In function ‘void demo::StrCpy(std::__cxx11::basic_string<char>::value_type (&)[N], const value_type*) [with long unsigned int N = 201]’,
inlined from ‘int main()’ at gcc.cpp:14:113:
gcc.cpp:11:17: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
11 | dest[N - 1] = 0; // make sure the terminating NUL is there
| ~~~~~~~~~~~~^~~
gcc.cpp: In function ‘int main()’:
gcc.cpp:19:14: note: at offset 206 to object ‘main()::a::m_lines’ with size 1206 declared here
19 | char m_lines[6][201];
| ^~~~~~~
感谢@StoryTeller-UnslanderMonica 将此识别为编译器错误。添加选项 -fno-peel-loops
解决问题。
使用 g++ 10.3 编译以下代码会给出一些可怕的警告(参见 https://godbolt.org/z/excrEzjsd):
#include <iostream>
#include <memory>
#include <vector>
#include <cstring>
#include <boost/algorithm/clamp.hpp>
namespace demo {
template <typename T, size_t N> constexpr std::size_t array_size(T (&)[N]) { return N; }
template <std::size_t N> inline void StrCpy(std::string::value_type (&dest)[N], const std::string::value_type *src) {
std::strncpy(dest, src, N);
dest[N - 1] = 0; // make sure the terminating NUL is there
}
template <std::size_t N> inline void StrCpy(std::string::value_type (&dest)[N], const std::string &src) { StrCpy(dest, src.c_str()); }
} // namespace demo
int main() {
struct a {
int m_num_lines;
char m_lines[6][201];
};
std::vector<std::string> lines{
"Line0",
"Line1",
"Line2",
"Line3",
"Line4",
"Line5",
"Line6",
"Line7",
"Line8",
"Line9",
"Line10",
};
auto theA = std::make_shared<a>();
theA->m_num_lines = boost::algorithm::clamp(lines.size(), 0, demo::array_size(theA->m_lines));
for (auto i = 0; i < theA->m_num_lines; i++) {
demo::StrCpy(theA->m_lines[i], lines[i]);
}
for (auto i = 0; i < theA->m_num_lines; i++) {
std::cout << theA->m_lines[i] << std::endl;
}
}
我不明白编译器实际上想说什么。我有错误还是编译器看到了幻影?顺便说一句:clang++ 和 MSVC 看不出这里有什么问题。
输出:
g++ -Wall -pedantic -O3 gcc.cpp -o gcc-bug
In file included from /usr/include/string.h:495,
from /usr/include/c++/10/cstring:42,
from gcc.cpp:4:
In function ‘char* strncpy(char*, const char*, size_t)’,
inlined from ‘void demo::StrCpy(std::__cxx11::basic_string<char>::value_type (&)[N], const value_type*) [with long unsigned int N = 201]’ at gcc.cpp:10:17,
inlined from ‘int main()’ at gcc.cpp:14:113:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:34: warning: ‘char* __builtin_strncpy(char*, const char*, long unsigned int)’ forming offset [1212, 1410] is out of the bounds [0, 1212] [-Warray-bounds]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In function ‘void demo::StrCpy(std::__cxx11::basic_string<char>::value_type (&)[N], const value_type*) [with long unsigned int N = 201]’,
inlined from ‘int main()’ at gcc.cpp:14:113:
gcc.cpp:11:17: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
11 | dest[N - 1] = 0; // make sure the terminating NUL is there
| ~~~~~~~~~~~~^~~
gcc.cpp: In function ‘int main()’:
gcc.cpp:19:14: note: at offset 206 to object ‘main()::a::m_lines’ with size 1206 declared here
19 | char m_lines[6][201];
| ^~~~~~~
感谢@StoryTeller-UnslanderMonica 将此识别为编译器错误。添加选项 -fno-peel-loops
解决问题。