Sunday, September 22, 2024

Re: Need some information about fork(2)

Hello,

sr@strahinja.org wrote on Sun, Sep 22, 2024 at 10:35:42PM +0200:

> Still, while most OSes (including OpenBSD) do free the leaked memory
> on program termination, there are some which don't.[1]
> [1]: https://stackoverflow.com/a/2975844/184064

I think you are spreading fear, uncertainty, and doubt here.

In fact, POSIX requires that many specific resources a process may
acquire from the OS be automatically released on process termination:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/_Exit.html

In particular, that includes malloc(3)ed memory, resources acquired
by open(2)ing file descriptors, and resources acquired in various
other ways, including "shared memory" sometimes cited as an example
of what might not get freed automatically by some operating systems.

> I think it is better to make a habit of free(3)ing every successfully
> allocated chunk of memory and err on the side of redundancy.

While the OpenBSD project is well-known for a strict style of
cautious and defensive programming with in-depth defense and multiple
layers of security, it certainly does not endorse what you are
suggesting here.

I think what you propose here is overblown way out of proportion.
In the unusual case where freeing everything right before exit(3)
is trivial, doing so will not do much harm, but it still isn't
really recommended because on an operating system that conforms
to POSIX, doing that is completely pointless and only makes the
code longer, harder to read and audit, maybe even somewhat confusing,
distracting code auditors into checking irrelevant points like whether
everything is *really* freed before exit(3). At the very least,
they do have to check that the attempted cleanup does not end up
in double free, which is a freal waste given that the cleanup
is unnecessary in the first place.

It's really a great chance for writing good code that, when something
catastrophic goes wrong, you can just err(3) out straight away no
matter what. Code doing that is very straightforward, very concise,
and easy to audit, hence more secure than code trying to clean up,
even if the cleanup isn't very difficult.

But even in a moderately small program like mandoc(1), you typically
have various open file descriptors stored in various program modules,
plus some complex data structures. So imagine a catastrophic
failure, like a malloc(3) failure, half a dozen or a dozen call stack
levels down in some private library, or even deep down inside some
recursive parsing algotithm. If you wanted to clean up in that
kind of a situation, you typically would have to bubble up all the
way back to the top of the call stack, signalling fatal failure in
all the function returns along the way. Then, on the top level, you
need to inspect various data structures, call cleanup functions
in orders that do not cause use after free, some of the cleanup
likely requiring iterative or even recursive algorithms, before
you can finally exit. Oh, and by the way, some information may
need to be passed up all the stack, like the reason of the failure
or the exit status.

What a nightmare. Your program will end up much more complex
and fragile and insecure than it needs to be - insecure
because after a catastrophic failure, chances are some of the
data structures are in an ususual or inconsistent state, risking
that the attempted cleanup causes invalid processing. I have even
seen cases where bugs caused programs that attempted to do cleanup
before exit(3), due to bugs in the cleanup code, ran off into
totally unexpected directions and failed to exit at all,
inspead doing wildly invalid processing of data that should never
have happened.

So no, when it's clear the program cannot recover from a problem
and needs to exit, then (with rare exceptions) just err(3) out
right away and refrain from attempting cleanup.


If there are specialized operating systems that violate POSIX
in extreme ways, then their unusual requirements should not
encumber recommendations for best general programming practice.
Leave unusual, specialised requirements of specialised systems
to the specialists dealing with those systems, do not spread
FUD to general-purpose programmers.

Yours,
Ingo

No comments:

Post a Comment