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.
Specific questions:
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).
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.
See for comparison the original code at 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):
<...>
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. 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
.
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). It's very rare when you'd want to avoid this option, and it's extremely useful.