Reputation: 802
I was going over some old C code (listed below) with a view to re-using it in a new project, and I realised I had left off the final return statement. The peculiar thing is that the routine worked perfectly and did return the correct file pointer. Can anyone explain to me why this is?
FILE* openforwrite(char *name, int binary)
{
//broken out from main to keep it tidy and allow multiple output files.
FILE *file;
//first see if it exists
file = fopen(name,"r");
if (file)
{ // it does, delete it
fclose(file);
if(remove(name)) bail("Output file already exists and cannot be deleted.");
}
//now lets re-create and open it for writing
if (binary)
file = fopen(name, "wb");
else
file = fopen(name, "w");
//check it actually opened
if (!file)
bail("Error opening output file.");
//and pass the pointer back
return file; // <-- I had omitted this line initially but the routine still worked
}
Upvotes: 3
Views: 1750
Reputation: 41252
The return value of the fopen
call would end up putting the file handle in the register that is commonly used for return values (e.g., eax
). If nothing changed that register value before the function exited, it could still be available for the caller. If, for example, you had one more function call after the fopen
and before the end of the function, then it would likely have overwritten the eax
register and failed for sure. As others have said, it is undefined behavior. Nonetheless, it is initially a very puzzling situation (and rather interesting).
Upvotes: 3
Reputation:
It merely happened to work. The compiler uses the stack for passing in arguments to functions, and to receive their return value. It also uses the stack for local variables and for temporary variables during calculations. When the function returned, the caller looked at a specific position in the stack for the return value. That value just happened to contain the file pointer value, because that was the last expression your function calculated.
Do not, ever, under any circumstances, assume that this will work this way again.
It may break for any number of reasons, including different compiler versions, different optimizations, or just because the compiler randomly decided to teach you a lesson.
Upvotes: 1
Reputation: 11162
The problem is that you invoked undefined behavior. It can seem to work, it can crash, and in the case of buffer overflows, it can delete files.
Upvotes: 0