简体   繁体   English

为什么声明不返回任何内容的函数的返回值只会导致gcc8中的运行时崩溃

[英]Why declaring a return value for a function that doesn't return nothing leads to run-time crash in gcc8 only

In the following code a function is declared/defined as int setYear(int year_h){year = year_h;} (instead of void setYear(...) , leading to run-time crash in gcc 8 AND with the flag -O[X] only. 在下面的代码中,将一个函数声明/定义为int setYear(int year_h){year = year_h;} (而不是void setYear(...) ,这导致gcc 8中的运行时崩溃,并带有标志-O[X]

Specific questions: 具体问题:

  1. What have changed in gcc 8, as it worked in gcc 7 ? 在gcc 7中,gcc 8发生了什么变化?
  2. Which flags can I use (if any) to generate a compilation error (rather than a warning) in gcc8 ? 我可以使用哪些标志(如果有的话)在gcc8中生成编译错误(而不是警告)?

main.cpp: main.cpp中:

#include <iostream>

using namespace std;

int year = 2000;
int setYear(int year_h){year = year_h;}

int main()
{
    cout << "Hello World!" << endl;
    setYear(2019);
    cout << "Year: " << year << endl;
    return 0;
}

Run-time crash with: 运行时崩溃:

g++-8 -O2  -o main main.cpp
./main
Hello World!
Hello World!
Segmentation fault (core dumped)

Works with: 适用于:

g++-7 -O2  -o main main.cpp

or 要么

g++-8 -o main main.cpp

EDIT: The question Omitting return statement in C++ answers my second question, but not the first one (on the difference between gcc 7 and gcc 8). 编辑: C ++中的省略省略语句的问题回答了我的第二个问题,但没有回答第一个问题(关于gcc 7和gcc 8的区别)。

Starting with GCC 8, your setYear function simply doesn't have the RET instruction when your source is compiled with -Og (at higher levels the function is inlined, making understanding what's going on harder), and the main where the function is called also lacks any continuation. 从GCC 8开始,当使用-Og编译源代码时, setYear函数根本没有RET指令(在更高级别上,该函数被内联,这使得了解正在发生的事情更加困难),并且该函数的main调用位置也缺乏任何延续。

See for comparison the original code at Compiler Explorer : 在Compiler Explorer中查看原始代码以进行比较:

<...>
setYear(int):
        mov     DWORD PTR year[rip], edi
.LC0:
        .string "Hello World!"
main:
<...>

And the code where return type int has been changed to void ( link ): 并且返回类型int的代码已更改为voidlink ):

<...>
setYear(int):
        mov     DWORD PTR year[rip], edi
        ret
.LC0:
        .string "Hello World!"
.LC1:
        .string "Year: "
main:
<...>

This omission alone is enough for execution flow to bump into main (the .string s are declared in another section), executing it again instead of returning to the point of call. 仅此一个遗漏就足以使执行流突入main (在另一节中声明了.string ),再次执行它而不是返回到调用点。 Apparenly, gcc doesn't consider it worth adding the RET instruction when there's no return statement in a function other than main returning non- void . 显然,当函数中除了main返回non- void之外没有return语句时,gcc认为不值得添加RET指令。

Of course, in many cases the problem is easily detectable by the compiler at the compilation stage. 当然,在许多情况下,编译器可以在编译阶段轻松检测到该问题。 I'd recommend using -Werror=return-type option, which makes this an error, unconditionally (unlike -Werror in general). 我建议使用-Werror=return-type选项,该选项无条件地使其成为错误(与-Werror通常不同)。 It's very rare when you'd want to avoid this option, and it's extremely useful. 当您要避免使用此选项时,这种情况非常罕见,它非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM