开启优化时GCC针对简单for循环的异常警告问题排查
关于GCC优化下的
-Wstringop-overflow=误报问题 问题背景
该示例定义了一个结构体,用于复制以空字符结尾的字符串,保留空终止符但不计入size成员:
struct A { char * data; std::size_t size; A(const char * d) : size{0} { if(d) { while(d[size++]); data = new char[size--]{}; // postfix because we keep the null-terminator (in data[size]) std::memcpy(data, d, size); } else data = new char[size+1]{}; // Keep the null-terminator so that data[0] remains valid } ~A() { delete[] data; } };
当编写遍历size成员的代码并开启GCC优化时:
int main() { A a("Hello"); for(std::size_t i = 0; i < a.size; ++i) std::cout << 'x'; // Do whatever, it doesn't matter return 0; }
会触发如下难以理解的警告:
In constructor 'A::A(const char*)', inlined from 'int main()' at <source>:32:16: <source>:19:24: warning: 'void* memcpy(void*, const void*, size_t)' writing between 9223372036854775808 and 18446744073709551614 bytes into a region of size between 1 and 9223372036854775807 [-Wstringop-overflow=] 19 | std::memcpy(data, d, size); | ~~~~~~~~~~~^~~~~~~~~~~~~~~ <source>:18:37: note: destination object of size [1, 9223372036854775807] allocated by 'operator new []' 18 | data = new char[size--]{}; // postfix because we keep the null-terminator (in data[size]) |
相关现象:
- 移除for循环或关闭编译器优化时,无警告;
- 在for循环前添加
std::cout输出时无警告,但循环后添加则警告仍存在; - 代码运行符合预期,无段错误;
- Clang无论是否开启优化均无此问题。
问题解答
代码有效性
提供的代码示例是完全有效的,不存在未定义行为:
- 构造函数中,
while(d[size++])会将size递增到字符串长度+1(包含末尾的'\0'); new char[size--]使用后缀递减,因此实际分配的内存大小是size的原始值(即字符串长度+1),分配完成后size被递减为字符串长度(不含'\0');- 后续
std::memcpy(data, d, size)的拷贝长度是正确的字符串长度,目标内存的大小足够容纳该数据,不会发生溢出。
GCC的问题根源
这是GCC静态分析器在优化(尤其是内联构造函数)后的误报。GCC的警告模块在追踪size变量的数据流时,结合main函数中for(i < a.size)的逻辑,错误地反向推导了size的取值范围,误以为memcpy的第三个参数是极大的无符号数值,从而触发了错误的-Wstringop-overflow=警告。
这种情况属于GCC特定的静态分析bug,并非代码本身存在问题。
内容的提问来源于stack exchange,提问作者Fareanor
相关产品推荐
相关产品推荐

