views:

317

answers:

3

I was trying to answer this question. As suggested by the accepted answer, the problem with that code is that not all control paths are returning a value. I tried this code on the VC9 compiler and it gave me a warning about the same. My question is why is just a warning and not an error? Also, in case the path which doesn't return a value gets executed, what will be returned by the function (It has to return something) ? Is it just whatever is there on top of the stack or is the dreaded undefined behavior again?

A: 

It is not an error because it may be the intended behaviour. For example, some encryption libraries use uninitialized local data as a step for seeding. As return values are kept in calling-convention and platform specific locations, this may help in some unusual (like the above) situations. In this case, the function returns whatever is left on the register used to return the return value.

Malkocoglu
Can you cite a specific example of an encryption library using uninitialized data as seeding? It sounds highly unlikely that a competent library would do that as the uninitialized data is anything but random in cryptographic terms.
Jonathan Leffler
Really? What encryption libraries do that? Relying on undefined behavior in an encryption library seems like a big potential security hole.
Jeremy Friesner
I would any day prefer a properly generated random number rather than uninitialized data as a seed. If you use MSVC++ debugger, you would regularly see that uninitialized data have fixed values (in debug version of program 0xCCCCCCCC, 0xCDCDCDCD).
Shailesh Kumar
@Jonathan Leffler: http://blogs.fsfe.org/tonnerre/archives/24
Malkocoglu
It was mistaken for a bug and caused big problem...
Malkocoglu
@Shailesh: I am not a fan of uninitialized data structures. I just remembered that, there was an occasion some programmers relied on this thing...
Malkocoglu
@Shailesh: Unfortunately, it is very hard to have properly generated random numbers (http://www.springerlink.com/content/kkpghbg30r1xce4m/). I also remember some cryptographer attacking the Intel hardware RNG on their chipsets by using some other hardware on that chip (maybe the sound card, i do not remember) so that he can keep the temperature of that area high enough that the RNG produced little entropy (as it relied on thermal noise)...
Malkocoglu
We are not safe even with hardware (True, they say) RNG systems. http://www.lightbluetouchpaper.org/2009/09/08/tuning-in-to-random-numbers/
Malkocoglu
@Jeremy Friesner: You can also look at the link I have written Jonathan about...
Malkocoglu
+2  A: 

I would guess it is only a warning because the compiler cannot always be 100% sure it is possible to not hit a return.

i.e. if you had:


-= source1.c =-
int func()
{
    if(doSomething())
    {
       return 0;
    }
}

-= source2.c =-
int doSomething()
{
    return 1;
}

The compiler in this case might not be able to know it will always hit the return, but you do. Of course this is terrible programming practice to rely on knowing how external code works.

As for what will actually be returned it depends on the platform. On x86 ABIs EAX is used for the return value (up to 32bits) so it will return what ever was placed in that register (which could be a return from something else, a temporary value or total garbage).

tyranid
+13  A: 

Failing to return a value from a function that has a non-void return type results in undefined behaviour, but is not a semantic error.

The reason for this, as far as I can determine, is largely historical.

C originally didn't have void and implicit int meant that most functions returned an int unless explicitly declared to return something else even if there was no intention to use the return value.

This means that a lot of functions returned an int but without explicitly setting a return value, but that was OK becase the callers would never use the return value for these functions.

Some functions did return a value, but used the implicit int because int was a suitable return type.

This means that pre-void code had lots of functions which nominally returned int but which could be declared to return void and lots of other functions that should return an int with no clear way to tell the difference. Enforcing return on all code paths of all non-void functions at any stage would break legacy code.

There is also the argument that some code paths in a function may be unreachable but this may not be easy to determine from a simple static analysis so why enforce an unnecessary return?

Charles Bailey
The static analysis can be easily explained if you think of `switch`, while you are strongly advised to provide a `default`, it is not required, and may not be necessary... but how is the compiler supposed to know it? On the other hand... you should treat warnings as errors while compiling, it's better.
Matthieu M.