The specification is pretty clear that __cxa_finalize should be called via the ELF destructor mechanism and invoke the registered __cxa_atexit callbacks for that particular shared object. But the ELF destructor order is not necessarily sequenced in a compatible way with the opposite __cxa_atexit order. This results in the wrong sequence of C++ destructor calls.
This specification seems to date back to an era where C++ implementations without a way to integrate with the system dynamic linker were common. Nowadays, I think we can do better by teaching the dynamic linker to invoke __cxa_atexit callbacks in the exact opposite order (regardless of DSOs), and do nothing in __cxa_finalize. But the current specification seems to preclude such a standards-conforming implementation, by explicitly tying the callbacks to the ELF destructor invocation.
The specification is pretty clear that
__cxa_finalize
should be called via the ELF destructor mechanism and invoke the registered__cxa_atexit
callbacks for that particular shared object. But the ELF destructor order is not necessarily sequenced in a compatible way with the opposite__cxa_atexit
order. This results in the wrong sequence of C++ destructor calls.This specification seems to date back to an era where C++ implementations without a way to integrate with the system dynamic linker were common. Nowadays, I think we can do better by teaching the dynamic linker to invoke
__cxa_atexit
callbacks in the exact opposite order (regardless of DSOs), and do nothing in__cxa_finalize
. But the current specification seems to preclude such a standards-conforming implementation, by explicitly tying the callbacks to the ELF destructor invocation.(@jwakely brought this up recently.)