Re: Breaking the crt1.o -> atexit() -> malloc() dependency

From: Kostik Belousov <kostikbel_at_gmail.com>
Date: Thu, 6 Mar 2008 11:48:10 +0200
On Wed, Mar 05, 2008 at 05:12:32PM -0800, Tim Kientzle wrote:
> There was some recent discussion on the commit mailing
> list about how to disentangle crt1.o from malloc().
> 
> Here's a design that I think addresses all of the
> issues people raised, including the POSIX requirement
> that atexit() always be able to support 32 registrations.
> It does it without using sbrk() or mmap(), either.
> 
> The basic idea is to lift the malloc() call up into
> atexit() and have atexit_register() use statically-allocated
> storage if atexit() didn't provide dynamically-allocated
> storage.
> 
> This basically changes atexit() to something like this pseudocode:
> 
> int atexit(void (*function)(void))
> {
> 	struct atexit *storage = malloc(sizeof(struct atexit));
> 
> 	/* Note: If malloc() fails, __atexit_register will try
> 	 * to statically allocate, so we don't check here
> 	 * for malloc() failure.  */
> 	return __atexit_register(function, storage);
> }
> 
> Then atexit_register either uses the block that was provided
> or grabs an item from a static pool if there wasn't one:
> 
> /* 32 required by POSIX plus a few for crt1.o */
> static struct atexit pool[40];
> 
> int atexit_register(void (*function)(void), struct atexit *storage)
> {
> 	if (storage == NULL) {
> 		storage = ... next item from static pool ...
> 	}
> 	storage.func = function;
> 	... add storage block to linked list ...
> }
> 
> Avoiding free() from the low-level code is a little trickier
> but I think it can be done by having the low-level code
> put (dynamically-allocated) blocks back onto a free list
> and having the higher-level atexit() release that list
> on the next registration.  This should handle the case
> of a dynamic library being repeatedly loaded and unloaded.
> Of course, it's unnecessary to release the atexit storage
> on program exit.
> 
> In particular, crt1.o can then call atexit_register(f, NULL)
> to register its exit functions without creating a dependency on
> malloc.
> 
> This does require that atexit() and atexit_register() be in
> separate source files, but I think it addresses all of the other
> concerns people have raised.

I mostly agree with proposal, but there is also __cxa_atexit().

And, besides the issue of the size of the static linked executables,
there is more exposed problem of atexit() memory leaks. See
http://lists.freebsd.org/pipermail/freebsd-stable/2008-February/040644.html

Received on Thu Mar 06 2008 - 08:48:44 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:28 UTC