在int函数上出现Segfault而没有返回,这是GCC11错误吗?[重复]

lokaqttq  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(120)
    • 此问题在此处已有答案**:

Checking return value of a function without return statement(3个答案)
Undefined behavior of a C function with no return type [duplicate](3个答案)
23小时前关门了。
今天我很惊讶:

#include <stdlib.h> // for the 'exit' call

int foo() {
    // return 0;
}

int main() {
    int res = foo();
    exit(res);
}

我知道忘记在foo中返回期望的整数值是不好的;但是你会期望这段代码出现segfault吗?
下面是GCC7.5的情况:

(thanassis)$ g++ -O3 -Wall  a.cc
a.cc: In function ‘int foo()’:
a.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]
     }
     ^

(thanassis)$ ./a.out 

(thanassis)$ gdb  ./a.out
GNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(No debugging symbols found in ./a.out)

(gdb) run
Starting program: /home/thanassis/a.out 
[Inferior 1 (process 24749) exited normally]

(gdb) quit

没问题,一切顺利.
是的,foo忽略了设置返回值,这意味着ABI(EAX)为任务选择的寄存器将有垃圾。
现在看看GCC11的情况:

(thanassis)$ g++ -O3 -Wall ./a.cc 
./a.cc: In function ‘int foo()’:
./a.cc:5:5: warning: no return statement in function returning non-void [-Wreturn-type]
    5 |     }
      |     ^

(thanassis)$ ./a.out 
Segmentation fault (core dumped)

(thanassis)$ gdb  ./a.out
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(No debugging symbols found in ./a.out)
(gdb) run
Starting program: /home/thanassis/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, 
    fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141
141     ../csu/libc-start.c: No such file or directory.
(gdb) bt
#0  0x00007ffff7ddbfaa in __libc_start_main (main=0x555555555044 <main>, argc=-136462205, argv=0x7fffff7ff0b0, init=0x555555555140 <__libc_csu_init>, 
    fini=0x5555555551b0 <__libc_csu_fini>, rtld_fini=0x7fffffffe0e8, stack_end=0x7fffff7ff0a8) at ../csu/libc-start.c:141
#1  0x000055555555507e in _start ()
(gdb)

现在这个,我没想到。
首先,堆栈帧看起来很混乱-main堆栈帧在哪里?
查看main的objdump输出...

$ objdump -d -S ./a.out 
...
Disassembly of section .text:

0000000000001040 <_Z3foov>:
#include <stdlib.h>

    int foo() {
    1040:       f3 0f 1e fa             endbr64 

0000000000001044 <main>:
        // return 0;
    }

    int main() {
    1044:       f3 0f 1e fa             endbr64 
    1048:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
    104f:       00 

0000000000001050 <_start>:
    1050:       f3 0f 1e fa             endbr64 
    1054:       31 ed                   xor    %ebp,%ebp
    1056:       49 89 d1                mov    %rdx,%r9
    1059:       5e                      pop    %rsi
    105a:       48 89 e2                mov    %rsp,%rdx
    105d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp

...看起来GCC决定"合并"堆栈帧?!
这看起来像是一个编译器错误。注意,忽略旧的编译器,它也不会在优化级别-O0-O1中出现-但在-O2之后会出现。
再次说明:我知道这是不好的形式,而且我确实使用了-Wall-Wextra--所以我在代码中修复了这个问题,但我想在这里分享一下,因为我从来没有想到一个返回int的函数不返回int来创建segfault(由于编译器创建的代码错过了堆栈帧)。

    • 更新**:另请注意,使用gcc而不是g++编译会创建正常代码。此问题仅在使用C++编译器编译代码时出现。
ki0zmccv

ki0zmccv1#

这不仅仅是“糟糕的形式”,而是undefined behavior
你的函数在声明返回值时失败了,而你试图使用那个返回值,这触发了未定义的行为,在-O3的情况下会导致崩溃。
这在C standard的第6.9.1p12节中详细说明:
如果到达了终止函数的},并且调用方使用了函数调用的值,则该行为未定义。
所以回答你的问题,不是编译器的错误,你只是做了一些你不应该做的事情。

相关问题