#357 Destructor ordering fix


GCC trunk uses atexit to call C++ static object destructors on MinGW:
each constructor (registered in .ctors) will call atexit to register
the corresponding destructor, so that they are called in reverse order
of construction (and interleaved with any atexit functions registered
by the user's constructor code) as required by the C++ standard.

If GCC trunk is configured with --disable-sjlj-exceptions, so that
DWARF-2 exception handling is used, a function calling
__register_frame_info will be registered in .ctors and one calling
__deregister_frame_info will be registered in .dtors. After
__deregister_frame_info is called, exception handling will no longer
work. Since exceptions may be raised and caught from within static
object destructors, this means that __deregister_frame_info must be
called after functions registered with atexit from within
constructors. Thus __do_global_ctors needs to call atexit to register
__do_global_dtors before, rather than after, calling the constructors.

This patch to gccmain.c fixes the libstdc++ test failures

FAIL: 27_io/objects/char/6.cc execution test
FAIL: 27_io/objects/wchar_t/6.cc execution test

for GCC trunk configured with --disable-sjlj-exceptions, with no
testsuite regressions.


  • Joseph Myers

    Joseph Myers - 2008-03-07
  • Danny Smith

    Danny Smith - 2008-03-07

    Logged In: YES
    Originator: NO

    The code in mingw's gccmain.c was copied (many years ago) from gcc/libgcc2.c #ifdef L__main block.

    The use of ctors/dtor in cygming_crtstuff.c to handle __[de]|register_frame_info was used to allow cygwin amd mingw to share the same code (cygwin's __do_global_[c|d}tors is cygwin1.dll and change that would cause cygwin-version compat issues)

    I think the right patch for mingw (ignoring cygin) would be to would be be to provide a mingw-specific __do_global_[c|d}tors so that we could explicitily control EH init/fini ordering regardless of ctor priorities

    like the one _now_ in libgcc2.c."L__main" block

    __do_global_dtors (void)
    static func_ptr *p = __DTOR_LIST__ + 1;
    while (*p)
    (*(p-1)) ();
    #if defined (EH_FRAME_SECTION_NAME)
    static int completed = 0;
    if (! completed)
    completed = 1;
    __deregister_frame_info (__EH_FRAME_BEGIN__);

    /* Run all the global constructors on entry to the program. */

    __do_global_ctors (void)
    static struct object object;
    __register_frame_info (__EH_FRAME_BEGIN__, &object);
    atexit (__do_global_dtors);

  • Joseph Myers

    Joseph Myers - 2008-03-07

    Logged In: YES
    Originator: YES

    Note that libgcc's copy of these functions is not used (despite the comment in gccmain.c suggesting it should be) because of the position of -lgcc in LIBGCC_SPEC. If you put -lgcc at the start of the spec, then you find the libgcc copies of these functions (with the same atexit ordering as the gccmain.c copies) have duplicate calls to __register_frame_info and __deregister_frame_info, so you need to do something like you suggest to stop them being duplicates.

  • Danny Smith

    Danny Smith - 2008-03-13

    Logged In: YES
    Originator: NO

    This is the main concern I have about your patch


    // dtors.C
    #include <stdio.h>
    class X
    int m_i;
    X(int i): m_i(i){}
    ~X(){printf ("in ~X()\n");} // compiler registers this directly
    // with atexit during construction

    X x(1);

    static void
    my_dtor () __attribute__((destructor)); // registered with atexit
    // via __do_global_[c|d]tors

    static void
    my_dtor ()
    { printf ("in my_dtor\n");}

    int main(){}

    Currently, functions that are registered with atexit directly by a ctor
    are run _after_ all functions in .dtor sections (which, as you explained,
    is why the libstdc++ tests fail), and we get

    in my_dtor
    in ~X()

    With your patch, the order is changed so that we get

    in ~X()
    in my_dtor

    which fixes the specific use of .dtors to handle EH frame cleanup and
    AFAICT is the only way to fix the bug for gcc 4.3.0

    Is this generic change of ordering justified by that?
    Or should we just change cygming-crtend to use direct atexit registration
    of frame cleanup from the frame registration ctor, and leave the fix till 4.3.1.


  • Earnie Boyd

    Earnie Boyd - 2013-02-13
    • status: open --> closed
    • milestone: --> 64bit_readiness

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

No, thanks