为什么为一个没有 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]
仅。
具体问题:
- gcc 8 在 gcc 7 中有哪些变化?
- 我可以使用哪些标志(如果有的话)在 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
不同)。当您想避免使用此选项时,这种情况非常罕见,而且它非常有用。
在下面的代码中,函数是 declared/defined 作为 int setYear(int year_h){year = year_h;}
(而不是 void setYear(...)
,导致 运行-time 在 gcc 8 中崩溃并且带有标志 -O[X]
仅。
具体问题:
- gcc 8 在 gcc 7 中有哪些变化?
- 我可以使用哪些标志(如果有的话)在 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
不同)。当您想避免使用此选项时,这种情况非常罕见,而且它非常有用。