超级怪异的gcc 4.7 segfault——Bug
Super weird segfault with gcc 4.7 -- Bug?
下面是我试图编译的一段代码:
#include <cstdio>
#define N 3
struct Data {
int A[N][N];
int B[N];
};
int foo(int uloc, const int A[N][N], const int B[N])
{
for(unsigned int j = 0; j < N; j++) {
for( int i = 0; i < N; i++) {
for( int r = 0; r < N ; r++) {
for( int q = 0; q < N ; q++) {
uloc += B[i]*A[r][j] + B[j];
}
}
}
}
return uloc;
}
int apply(const Data *d)
{
return foo(4,d->A,d->B);
}
int main(int, char **)
{
Data d;
for(int i = 0; i < N; ++i) {
for(int j = 0; j < N; ++j) {
d.A[i][j] = 0.0;
}
d.B[i] = 0.0;
}
int res = 11 + apply(&d);
printf("%dn",res);
return 0;
}
是的,它看起来很奇怪,目前根本没有做任何有用的事情,但它是我最初遇到问题的一个更大程序的最简洁的版本。
它使用GCC(G++)4.4和4.6编译和运行都很好,但如果我使用GCC 4.7,并启用第三级优化:
g++-4.7 -g -O3 prog.cpp -o prog
我在运行它时遇到了分段错误。Gdb并没有提供太多关于错误的信息:
(gdb) run
Starting program: /home/kalle/work/code/advect_diff/c++/strunt
Program received signal SIGSEGV, Segmentation fault.
apply (d=d@entry=0x7fffffffe1a0) at src/strunt.cpp:25
25 int apply(const Data *d)
(gdb) bt
#0 apply (d=d@entry=0x7fffffffe1a0) at src/strunt.cpp:25
#1 0x00000000004004cc in main () at src/strunt.cpp:34
我试着用不同的方式调整代码,看看错误是否消失了。似乎有必要在foo中拥有所有四个循环级别,而我无法通过一个级别的函数调用来复制它。哦,是的,最外层的循环必须使用无符号循环索引。
我开始怀疑这是编译器或运行时中的一个错误,因为它是4.7版本特有的,我看不出哪些内存访问是无效的。
如果能深入了解正在发生的事情,我们将不胜感激。
GCC的C版本也可能出现同样的情况,只需稍微修改代码即可。
我的系统是:
Debian喘息Linux 3.2.0-4-amd64GCC 4.7.2-5
好的,所以我看了gdb提供的拆解,但恐怕它对我来说没有多大意义:
Dump of assembler code for function apply(Data const*):
0x0000000000400760 <+0>: push %r13
0x0000000000400762 <+2>: movabs $0x400000000,%r8
0x000000000040076c <+12>: push %r12
0x000000000040076e <+14>: push %rbp
0x000000000040076f <+15>: push %rbx
0x0000000000400770 <+16>: mov 0x24(%rdi),%ecx
=> 0x0000000000400773 <+19>: mov (%rdi,%r8,1),%ebp
0x0000000000400777 <+23>: mov 0x18(%rdi),%r10d
0x000000000040077b <+27>: mov $0x4,%r8b
0x000000000040077e <+30>: mov 0x28(%rdi),%edx
0x0000000000400781 <+33>: mov 0x2c(%rdi),%eax
0x0000000000400784 <+36>: mov %ecx,%ebx
0x0000000000400786 <+38>: mov (%rdi,%r8,1),%r11d
0x000000000040078a <+42>: mov 0x1c(%rdi),%r9d
0x000000000040078e <+46>: imul %ebp,%ebx
0x0000000000400791 <+49>: mov $0x8,%r8b
0x0000000000400794 <+52>: mov 0x20(%rdi),%esi
当我看到这个时,我应该看到什么?
编辑2015-08-13:这似乎在g++4.8及更高版本中得到了修复。
您从未初始化过d
。它的值是不确定的,尝试对其内容进行数学运算是未定义的行为。(即使尝试读取其值而不对其执行任何操作也是未定义的行为。)初始化d
,看看会发生什么。
现在您已经初始化了d
,但它仍然失败,这看起来像是一个真正的编译器错误。尝试更新到4.7.3或4.8.2;如果问题仍然存在,请提交错误报告。(已知错误的列表目前似乎是空的,或者至少链接指向了只列出非错误的地方。)
不幸的是,它确实是gcc中的一个bug。我一点也不知道它在那里做什么,但为apply函数生成的程序集是(我在没有主btw的情况下编译它,它有foo内联):
_Z5applyPK4Data:
pushq %r13
movabsq $17179869184, %r8
pushq %r12
pushq %rbp
pushq %rbx
movl 36(%rdi), %ecx
movl (%rdi,%r8), %ebp
movl 24(%rdi), %r10d
而恰恰在movl (%rdi,%r8), %ebp
,它会崩溃,因为它向$rdi
(第一个参数,因此是指向Data
的指针)添加了一个无意义的0x400000000
并取消了对它的引用
- C++中带有List类的迭代器Segfault
- Clang bug?使用指针作为模板参数
- 使用Vulkan hpp vk::enumerateInstanceVersion()会导致segfault
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- std::partition segfault issue
- OpenSSL: EC_POINT_set_compressed_coordinates_GFp segfault
- 类无法访问自己的私有静态 constexpr 方法 - Clang bug?
- 检查nullptr是否100%保护内存布局不受segfault影响
- OpenCV Tracker 属性访问在 ARM 上因 SEGFAULT 而失败,但在 X86_64 中工作
- 为什么优化大型 std::vector 数组会导致 SegFault?
- C++segfault,可重复的例子
- 带有zip_source_buffer的libzip会导致数据损坏和/或segfault
- C++:编译对无关派生类、bug或特性的函数调用
- 导致SegFault C++的析构函数
- 从引用的Vector获取SEGFAULT
- 尝试读取/写入Graphviz DAG值的工作证明会导致segfault
- Segfault如果更改派生类的指针值
- Microsoft VC++, vsnprintf, and Pipes (IO) Bug
- 超级怪异的gcc 4.7 segfault——Bug