Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 14 Jun 2012 14:32:47 +0200
From: Szabolcs Nagy <nsz@...t70.net>
To: musl@...ts.openwall.com
Subject: Re: Timing of destructors?

* Richard Pennington <rich@...nware.com> [2012-06-14 06:01:45 -0500]:
> which doesn't print "after". This is because stdio is cleaned up before 
> destructors are called in exit.c. Using stdio in destructors can be handy for 
> debugging (if nothing else). Would it be evil to modify exit.c to look like 
> this?:
> 
> void exit(int code)
> {
>         static int lock;
> 
>         /* If more than one thread calls exit, hang until _Exit ends it all */
>         while (a_swap(&lock, 1)) __syscall(SYS_pause);
> 
>         /* Destructor s**t is kept separate from atexit to avoid bloat */
>         if (libc.fini) libc.fini();
>         if (libc.ldso_fini) libc.ldso_fini();
> 
>         /* Only do atexit & stdio flush if they were actually used */
>         __funcs_on_exit();
>         __fflush_on_exit();
> 
>         _Exit(code);
>         for(;;);
> }
> 
> The change is to move the *_on_exit() calls to after the destructors have been 
> called.
> 

the c standard does not say anything about destructors
(obviously) otherwise the cleanup order is atexit handlers
then stdio cleanups.

c++ specifies that destructors come before stdio cleanups
(interleaved with atexit handlers based on the execution order
of the constructor and atexit call)

more precisely c++11 "18.5 Start and termination":

"The function exit() has additional behavior in this International Standard:
-- First, objects with thread storage duration and associated with the current thread are destroyed.
   Next, objects with static storage duration are destroyed and functions registered by calling atexit
   are called. See 3.6.3 for the order of destructions and calls. (Automatic objects are not
   destroyed as a result of calling exit().)
   If control leaves a registered function called by exit because the function does not provide a
   handler for a thrown exception, terminate() shall be called (15.5.1).
-- Next, all open C streams (as mediated by the function signatures declared in <cstdio>) with
   unwritten buffered data are flushed, all open C streams are closed, and all files created by calling
   tmpfile() are removed.
-- Finally, control is returned to the host environment. If status is zero or EXIT_SUCCESS, an
   implementation-defined form of the status successful termination is returned. If status is EXIT_-
   FAILURE, an implementation-defined form of the status unsuccessful termination is returned.
   Otherwise the status returned is implementation-defined."


of course gcc destructor attribute is not the same as c++
destructors of static duration objects but i'd expect them
to behave the same way ie. come before __fflush_on_exit();

i'm not sure about __funcs_on_exit() and destructor order,
i think destructors should come later as they are 'registered'
earlier than the atexit handlers

so i think the most correct is

/* Only do atexit if they were actually used */
__funcs_on_exit();
/* Destructor s**t is kept separate from atexit to avoid bloat */
if (libc.fini) libc.fini();
if (libc.ldso_fini) libc.ldso_fini();
/* Only do stdio flush if they were actually used */
__fflush_on_exit();
_Exit(code);

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.