GCC 12 generates wrong code
Calling exit()
in a C++ application results in std::terminate()
being called.
The std::ios_base::Init::~Init()
destructor flushes std::cout
, std::cerr
and std::clog
. The flush of std::cerr
results in terminate being called.
The ios_base
class uses a sentry to check the state. The code in it's destructor is:
if (bool(_M_os.flags() & ios_base::unitbuf) && !uncaught_exception())
The std::cerr
object has ios_base::unitbuf
set so uncaught_exception()
is called. This call gets the cxa globals:
__cxa_eh_globals *globals = __cxa_get_globals ();
The __cxa_get_globals()
checks if the ec_globals
init
object:
static __eh_globals_init init;
to see if it is still valid and the state is:
(gdb) p /x init
$2 = {
_M_key = 0x13010001,
_M_init = 0x1
}
However the static destructor has run and the POSIX key has been deleted. This results in std::terminate()
being called.
The code for the destructor on ARM is:
006562e0 <__eh_globals_init::~__eh_globals_init()>:
6562e0: 7903 ldrb r3, [r0, #4]
6562e2: b510 push {r4, lr}
6562e4: 4604 mov r4, r0
6562e6: b90b cbnz r3, 6562ec <__eh_globals_init::~__eh_globals_init()+0xc>
6562e8: 4620 mov r0, r4
6562ea: bd10 pop {r4, pc}
6562ec: 6800 ldr r0, [r0, #0]
6562ee: f04d fe6b bl 6a3fc8 <pthread_key_delete>
6562f2: 4620 mov r0, r4
6562f4: bd10 pop {r4, pc}
and for aarch64
it is:
0000000010222c30 <__eh_globals_init::~__eh_globals_init()>:
10222c30: 39401001 ldrb w1, [x0, #4]
10222c34: 35000041 cbnz w1, 10222c3c <__eh_globals_init::~__eh_globals_init()+0xc>
10222c38: d65f03c0 ret
10222c3c: a9bf7bfd stp x29, x30, [sp, #-16]!
10222c40: 910003fd mov x29, sp
return pthread_key_delete (__key);
10222c44: b9400000 ldr w0, [x0]
10222c48: 94008806 bl 10244c60 <pthread_key_delete>
10222c4c: a8c17bfd ldp x29, x30, [sp], #16
10222c50: d65f03c0 ret
The _M_init
boolean is not set to false
.