int foo(void) {
/* do stuff */
/* no return here */
}
int main(void) {
/* Trying to use the (not) returned value causes UB */
int value = foo();
return 0;
}
When a function is declared to return a value then it has to do so on every possible code path through it. Undefined behavior occurs as soon as the caller (which is expecting a return value) tries to use the return value1.
Note that the undefined behaviour happens only if the caller attempts to use/access the value from the function. For example,
int foo(void) {
/* do stuff */
/* no return here */
}
int main(void) {
/* The value (not) returned from foo() is unused. So, this program
* doesn't cause *undefined behaviour*. */
foo();
return 0;
}
The main()
function is an exception to this rule in that it is possible for it to be terminated without a return statement because an assumed return value of 0
will automatically be used in this case2.
1 (ISO/IEC 9899:201x, 6.9.1/12)
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
2 (ISO/IEC 9899:201x, 5.1.2.2.3/1)
reaching the } that terminates the main function returns a value of 0.