Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return vs exit in FreeBSD /bin/ and /usr/bin

I noticed that the FreeBSD code in /bin and /usr/bin have some fix to use exit instead of return, what does that mean?

All I have in my thought is that the return statement may cause vfork(2) to corrupt the stack frame, is that the only reason for this? If that was true, then why just a portion of the commands in /bin and /usr/bin got fixes, not all of them?

like image 843
oxnz Avatar asked Oct 30 '22 15:10

oxnz


2 Answers

According to 5.1.2.2.3p1

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument

This rules out your corrupt the stack frame theory; return 0; is functionally identical to exit(0); for conforming C implementations (at least for non-recursive main entry points).

I would suggest that this change was merely stylistic, or perhaps guided by ignorance. Another possibility is that the author has the desire to transform main into a recursive function (or main has already been turned into a recursive function; idk, I just did a quick grep and it doesn't seem immediately recursive). Finally, as the last grim alternative, perhaps the C implementation that FreeBSD uses is non-conforming (I sure hope not!)...

edit: It just occurred to me by reading through this answer that this could have been a work-around for a compiler bug, but alas I checked the source code for usage of atexit and could find no reason to pursue this line of reasoning any further.

like image 149
autistic Avatar answered Nov 15 '22 06:11

autistic


Let's see if I can amalgamate the various links provided by others into an appropriate answer.


As far as the C language is concerned, there is no difference.

A call to exit() does

  1. call the functions registered with atexit();
  2. flushes and closes the output streams;
  3. removes files opened with tmpfile();
  4. returns control to the environment.

A return <n> from main is equivalent to exit( <n> ).


Some flawed static code analyzers think different.

As far as the C language is concerned, memory allocated by main() and not free()d is leaked. Unix cleans up at process termination, but not all operating systems do (!).

Apparently, some static code analyzers consider memory still allocated at the point of exit() to be not leaked (while they do for return from main()), which is why that commit was made (to get rid of the warning).

This is a workaround for a bug in the code analyzer.


As far as the C++ language is concerned, there is a lot of difference.

When you return from main(), you are leaving the scope of the function, which means local objects get destroyed.

Since C++ programmers enjoy the benefits of deterministic destruction (as opposed to e.g. Java which might or might not execute your destructor even on VM termination...), they tend to make their destructors do more than just freeing memory. Network connections, temporary files, terminal windows locked by ncurses, all that kind of goodness, which C programmers would have to care for manually or use atexit() for.

When you call std::exit() from main(), that function directly turns over control to the runtime. The main() function never returns, the process gets terminated without calling the destructors of main()-local objects.

Moreover, while std::exit() is defined to flush and close the C output streams, there is no such provision for the C++ output streams.

like image 20
DevSolar Avatar answered Nov 15 '22 07:11

DevSolar