我在 OSX 上的 gcc 中不断得到 "Segmentation fault: 11",但在 Windows 上工作
I keep getting "Segmentation fault: 11" in gcc on OSX, but works on Windows
该程序编译正常,但当我为 mult(x,y) 的第一个参数输入负数时无法执行。它显示消息 "Segmentation fault: 11"。我在 Windows 上试过了,效果很好。
在X代码中编译时的错误信息是:Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff5f3ffffc)
为什么这在 OSX (El Capitan) 上不起作用但在 Windows 上没问题?非常感谢!
#include <stdio.h>
signed succ(signed a)
{
return a+1;
}
signed pre(signed b)
{
return b-1;
}
signed add(signed c, signed d)
{
if(d == 0) return c;
return succ(add(c, pre(d)));
}
signed sub(signed e, signed f)
{
if(f == 0) return e;
return pre(sub(e, pre(f)));
}
signed mult(signed g, signed h)
{
if(h == 0 || g == 0) return 0;
return add(g,mult(g,pre(h)));
}
int main()
{
printf("mult -2,2: %i\n", mult(-2,2));
return 0;
}
由于堆栈溢出而崩溃,mult
和 add
函数被递归调用。
虽然最好使用调试器,但在每个函数中添加一个printf
可以帮助观察程序流程。例如将 mult
更改为:
signed mult(signed g, signed h)
{
printf(" mult %d %d\n", g, h);
if(h == 0 || g == 0) return 0;
return add(g,mult(g,pre(h)));
}
和其他函数类似...输出是:
mult -2 2
pre 2
mult -2 1
pre 1
mult -2 0
add -2 0
add -2 -2
pre -2
add -2 -3
pre -3
add -2 -4
pre -4
add -2 -5
pre -5
add -2 -6
pre -6
add -2 -7
pre -7
add -2 -8
pre -8
add -2 -9
pre -9
add -2 -10
...
并且它继续调用 add
,第二个参数递减,直到它崩溃。 add
中的条件 if(d == 0)
仅当该参数溢出时才会变为 true
(在 sizeof signed
为 4,即 32 位的情况下,将在超过 40 亿次迭代后发生).
当它工作时,我唯一能想到的就是编译器进行优化并可能删除函数调用。
在我的 Windows x64 机器上尝试使用来自 MinGW 的 gcc
构建的原始程序:
构建时崩溃:gcc file.c
用gcc -O3 file.c
构建成功运行(这里我改变了优化级别)
在使用 -O3
构建的可执行文件上,我 运行 objdump -S a.exe > a.lst
这是反汇编的 mult
函数:
0000000000401550 <mult>:
401550: 53 push %rbx
401551: 48 83 ec 20 sub [=12=]x20,%rsp
401555: 31 c0 xor %eax,%eax
401557: 85 d2 test %edx,%edx
401559: 89 cb mov %ecx,%ebx
40155b: 75 06 jne 401563 <mult+0x13>
40155d: 48 83 c4 20 add [=12=]x20,%rsp
401561: 5b pop %rbx
401562: c3 retq
401563: 85 c9 test %ecx,%ecx
401565: 74 f6 je 40155d <mult+0xd>
401567: 83 fa 01 cmp [=12=]x1,%edx
40156a: 75 08 jne 401574 <mult+0x24>
40156c: 01 d8 add %ebx,%eax
40156e: 48 83 c4 20 add [=12=]x20,%rsp
401572: 5b pop %rbx
401573: c3 retq
401574: 83 fa 02 cmp [=12=]x2,%edx
401577: 89 c8 mov %ecx,%eax
401579: 74 f1 je 40156c <mult+0x1c>
40157b: 83 ea 03 sub [=12=]x3,%edx
40157e: e8 cd ff ff ff callq 401550 <mult>
401583: 85 c0 test %eax,%eax
401585: 74 0b je 401592 <mult+0x42>
401587: 01 d8 add %ebx,%eax
401589: 74 0d je 401598 <mult+0x48>
40158b: 01 d8 add %ebx,%eax
40158d: 01 d8 add %ebx,%eax
40158f: 90 nop
401590: eb dc jmp 40156e <mult+0x1e>
401592: 89 d8 mov %ebx,%eax
401594: 01 d8 add %ebx,%eax
401596: eb f5 jmp 40158d <mult+0x3d>
401598: 89 d8 mov %ebx,%eax
40159a: 01 d8 add %ebx,%eax
40159c: eb d0 jmp 40156e <mult+0x1e>
40159e: 90 nop
40159f: 90 nop
可以看出,它没有调用任何其他函数,只调用它自己 (callq 401550 <mult>
)。所以编译器优化/内联了所有其他调用。并通过添加 printf
(但仅在此函数中,不破坏优化),输出为:
mult -2 2
mult -2 1
mult -2 0
mult -2,2: -4
看起来好像优化器中有一个盲点。我认为应该崩溃的代码。查看优化后的代码会很有趣。我看不出什么会导致优化器混淆。也许优化器没有考虑可能发生的符号翻转。所以它假设一个负数减一将永远是一个负数,例如...
该程序编译正常,但当我为 mult(x,y) 的第一个参数输入负数时无法执行。它显示消息 "Segmentation fault: 11"。我在 Windows 上试过了,效果很好。
在X代码中编译时的错误信息是:Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff5f3ffffc)
为什么这在 OSX (El Capitan) 上不起作用但在 Windows 上没问题?非常感谢!
#include <stdio.h>
signed succ(signed a)
{
return a+1;
}
signed pre(signed b)
{
return b-1;
}
signed add(signed c, signed d)
{
if(d == 0) return c;
return succ(add(c, pre(d)));
}
signed sub(signed e, signed f)
{
if(f == 0) return e;
return pre(sub(e, pre(f)));
}
signed mult(signed g, signed h)
{
if(h == 0 || g == 0) return 0;
return add(g,mult(g,pre(h)));
}
int main()
{
printf("mult -2,2: %i\n", mult(-2,2));
return 0;
}
由于堆栈溢出而崩溃,mult
和 add
函数被递归调用。
虽然最好使用调试器,但在每个函数中添加一个printf
可以帮助观察程序流程。例如将 mult
更改为:
signed mult(signed g, signed h)
{
printf(" mult %d %d\n", g, h);
if(h == 0 || g == 0) return 0;
return add(g,mult(g,pre(h)));
}
和其他函数类似...输出是:
mult -2 2
pre 2
mult -2 1
pre 1
mult -2 0
add -2 0
add -2 -2
pre -2
add -2 -3
pre -3
add -2 -4
pre -4
add -2 -5
pre -5
add -2 -6
pre -6
add -2 -7
pre -7
add -2 -8
pre -8
add -2 -9
pre -9
add -2 -10
...
并且它继续调用 add
,第二个参数递减,直到它崩溃。 add
中的条件 if(d == 0)
仅当该参数溢出时才会变为 true
(在 sizeof signed
为 4,即 32 位的情况下,将在超过 40 亿次迭代后发生).
当它工作时,我唯一能想到的就是编译器进行优化并可能删除函数调用。
在我的 Windows x64 机器上尝试使用来自 MinGW 的 gcc
构建的原始程序:
构建时崩溃:
gcc file.c
用
gcc -O3 file.c
构建成功运行(这里我改变了优化级别)
在使用 -O3
构建的可执行文件上,我 运行 objdump -S a.exe > a.lst
这是反汇编的 mult
函数:
0000000000401550 <mult>:
401550: 53 push %rbx
401551: 48 83 ec 20 sub [=12=]x20,%rsp
401555: 31 c0 xor %eax,%eax
401557: 85 d2 test %edx,%edx
401559: 89 cb mov %ecx,%ebx
40155b: 75 06 jne 401563 <mult+0x13>
40155d: 48 83 c4 20 add [=12=]x20,%rsp
401561: 5b pop %rbx
401562: c3 retq
401563: 85 c9 test %ecx,%ecx
401565: 74 f6 je 40155d <mult+0xd>
401567: 83 fa 01 cmp [=12=]x1,%edx
40156a: 75 08 jne 401574 <mult+0x24>
40156c: 01 d8 add %ebx,%eax
40156e: 48 83 c4 20 add [=12=]x20,%rsp
401572: 5b pop %rbx
401573: c3 retq
401574: 83 fa 02 cmp [=12=]x2,%edx
401577: 89 c8 mov %ecx,%eax
401579: 74 f1 je 40156c <mult+0x1c>
40157b: 83 ea 03 sub [=12=]x3,%edx
40157e: e8 cd ff ff ff callq 401550 <mult>
401583: 85 c0 test %eax,%eax
401585: 74 0b je 401592 <mult+0x42>
401587: 01 d8 add %ebx,%eax
401589: 74 0d je 401598 <mult+0x48>
40158b: 01 d8 add %ebx,%eax
40158d: 01 d8 add %ebx,%eax
40158f: 90 nop
401590: eb dc jmp 40156e <mult+0x1e>
401592: 89 d8 mov %ebx,%eax
401594: 01 d8 add %ebx,%eax
401596: eb f5 jmp 40158d <mult+0x3d>
401598: 89 d8 mov %ebx,%eax
40159a: 01 d8 add %ebx,%eax
40159c: eb d0 jmp 40156e <mult+0x1e>
40159e: 90 nop
40159f: 90 nop
可以看出,它没有调用任何其他函数,只调用它自己 (callq 401550 <mult>
)。所以编译器优化/内联了所有其他调用。并通过添加 printf
(但仅在此函数中,不破坏优化),输出为:
mult -2 2
mult -2 1
mult -2 0
mult -2,2: -4
看起来好像优化器中有一个盲点。我认为应该崩溃的代码。查看优化后的代码会很有趣。我看不出什么会导致优化器混淆。也许优化器没有考虑可能发生的符号翻转。所以它假设一个负数减一将永远是一个负数,例如...