没有返回的 int 函数出现段错误。这是 GCC11 的错误吗?

tts*_*ras -3 c c++ gcc

今天我对此感到惊讶:

\n
#include <stdlib.h> // for the 'exit' call\n\nint foo() {\n    // return 0;\n}\n\nint main() {\n    int res = foo();\n    exit(res);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我知道忘记返回 ; 中的预期整数值不是好形式foo。但你会期望这段代码出现段错误吗?

\n

以下是 GCC7.5 中发生的情况:

\n
(thanassis)$ g++ -O3 -Wall  a.cc\na.cc: In function \xe2\x80\x98int foo()\xe2\x80\x99:\na.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]\n     }\n     ^\n\n(thanassis)$ ./a.out \n\n(thanassis)$ gdb  ./a.out\nGNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2\nCopyright (C) 2021 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\nType "show copying" and "show warranty" for details.\nThis GDB was configured as "x86_64-linux-gnu".\nType "show configuration" for configuration details.\nFor bug reporting instructions, please see:\n<https://www.gnu.org/software/gdb/bugs/>.\nFind the GDB manual and other documentation resources online at:\n    <http://www.gnu.org/software/gdb/documentation/>.\n\nFor help, type "help".\nType "apropos word" to search for commands related to "word"...\nReading symbols from ./a.out...\n(No debugging symbols found in ./a.out)\n\n(gdb) run\nStarting program: /home/thanassis/a.out \n[Inferior 1 (process 24749) exited normally]\n\n(gdb) quit\n
Run Code Online (Sandbox Code Playgroud)\n

没问题。都好。

\n

是的,忽略设置返回值的事实foo意味着 ABI (EAX) 为任务选择的寄存器将有垃圾。任何。

\n

现在看看 GCC11 会发生什么:

\n
(thanassis)$ g++ -O3 -Wall ./a.cc \n./a.cc: In function \xe2\x80\x98int foo()\xe2\x80\x99:\n./a.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]\n    5 |     }\n      |     ^\n\n(thanassis)$ ./a.out \nSegmentation fault (core dumped)\n\n(thanassis)$ gdb  ./a.out\nGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2\nCopyright (C) 2020 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\nType "show copying" and "show warranty" for details.\nThis GDB was configured as "x86_64-linux-gnu".\nType "show configuration" for configuration details.\nFor bug reporting instructions, please see:\n<http://www.gnu.org/software/gdb/bugs/>.\nFind the GDB manual and other documentation resources online at:\n    <http://www.gnu.org/software/gdb/documentation/>.\n\nFor help, type "help".\nType "apropos word" to search for commands related to "word"...\nReading symbols from ./a.out...\n(No debugging symbols found in ./a.out)\n(gdb) run\nStarting program: /home/thanassis/a.out \n\nProgram received signal SIGSEGV, Segmentation fault.\n0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, \n    fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141\n141     ../csu/libc-start.c: No such file or directory.\n(gdb) bt\n#0  0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, \n    fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141\n#1  0x000055555555507e in _start ()\n(gdb) \n
Run Code Online (Sandbox Code Playgroud)\n

现在这个情况,是我没想到的。

\n

其一,堆栈帧似乎一团糟——main堆栈帧在哪里?

\n

查看 objdump 的输出main...

\n
$ objdump -d -S ./a.out \n...\nDisassembly of section .text:\n\n0000000000001040 <_Z3foov>:\n#include <stdlib.h>\n\n    int foo() {\n    1040:       f3 0f 1e fa             endbr64 \n\n0000000000001044 <main>:\n        // return 0;\n    }\n\n    int main() {\n    1044:       f3 0f 1e fa             endbr64 \n    1048:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)\n    104f:       00 \n\n0000000000001050 <_start>:\n    1050:       f3 0f 1e fa             endbr64 \n    1054:       31 ed                   xor    %ebp,%ebp\n    1056:       49 89 d1                mov    %rdx,%r9\n    1059:       5e                      pop    %rsi\n    105a:       48 89 e2                mov    %rsp,%rdx\n    105d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp\n
Run Code Online (Sandbox Code Playgroud)\n

...看起来 GCC 决定“合并”堆栈帧?!

\n

对我来说这看起来像是一个编译器错误。请注意,忽略较旧的编译器,它也不会显示优化级别-O0--O1但它会在-O2.

\n

再次强调一下:我知道这是不好的形式,而且我确实使用了-Walland -Wextra- 所以我确实在代码中修复了这个问题。但我想我应该在这里分享这一点,因为我从来没有预料到一个返回 int 的函数不会返回 int 来创建段错误(由于编译器创建的代码错过了堆栈帧)。

\n

更新:另请注意,使用gcc和 not进行编译g++会创建正常的代码。该问题仅在使用 C++ 编译器编译代码时才会出现。

\n

dbu*_*ush 9

这不仅仅是“糟糕的形式”,它是未定义的行为

您的函数在声明返回值时未能返回值,并且您正在尝试使用该返回值。这会触发未定义的行为,在这种-O3情况下会导致崩溃。

C 标准第 6.9.1p12 节对此进行了详细说明:

如果}到达终止函数的 ,并且调用者使用函数调用的值,则行为未定义。

所以回答你的问题,这不是编译器错误。你只是做了一些你不应该做的事。

  • 注意:C++ 标准对此要求更加严格,无论调用者是否使用结果,它都是 UB。 (5认同)