[英]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: 具体问题:
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
的代码已更改为void
( link ):
<...>
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.