为什么为一个没有 return 的函数声明一个 return 值只会在 gcc8 中导致 运行-time 崩溃

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

在下面的代码中,函数是 declared/defined 作为 int setYear(int year_h){year = year_h;}(而不是 void setYear(...),导致 运行-time 在 gcc 8 中崩溃并且带有标志 -O[X] 仅。

具体问题:

  1. gcc 8 在 gcc 7 中有哪些变化?
  2. 我可以使用哪些标志(如果有的话)在 gcc8 中生成编译错误(而不是警告)?

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;
}

运行-时间崩溃:

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

适用于:

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

g++-8 -o main main.cpp

编辑:问题 Omitting return statement in C++ 回答了我的第二个问题,但没有回答第一个问题(关于 gcc 7 和 gcc 8 之间的区别)。

从 GCC 8 开始,当您的源代码使用 -Og 编译时,您的 setYear 函数根本没有 RET 指令(在更高级别上,该函数是内联的,使得更难理解发生了什么),并且调用函数的 main 也没有任何延续。

查看比较the original code at Compiler Explorer:

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

并且 return 类型 int 的代码已更改为 void (link):

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

仅此遗漏就足以让执行流程撞到 main.string 是在另一节中声明的),再次执行它而不是 return 到该点电话。显然,当函数中除了 main return 非 void 之外没有 return 语句时,gcc 认为不值得添加 RET 指令。

当然,在很多情况下,编译器在编译阶段很容易检测到问题。我建议使用 -Werror=return-type 选项,这会无条件地导致错误(与一般的 -Werror 不同)。当您想避免使用此选项时,这种情况非常罕见,而且它非常有用。