This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/81337] New: g++.dg/gcov/pr16855.C etc. FAIL
- From: "ro at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 06 Jul 2017 08:31:42 +0000
- Subject: [Bug c++/81337] New: g++.dg/gcov/pr16855.C etc. FAIL
- Auto-submitted: auto-generated
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81337
Bug ID: 81337
Summary: g++.dg/gcov/pr16855.C etc. FAIL
Product: gcc
Version: 8.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: ro at gcc dot gnu.org
CC: jason at gcc dot gnu.org, marxin at gcc dot gnu.org,
nathan at gcc dot gnu.org
Target Milestone: ---
Target: *-*-solaris2.12, *-*-darwin*, *-*-freebsd*
Created attachment 41693
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41693&action=edit
reduced testcase
g++.dg/gcov/pr16855.C and it's companion g++.dg/gcov/pr16855-priority.C for
targets with constructor priority support have been FAILing on Solaris 12 only
(it does work on Solaris 10 and 11) since they were first added:
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++11 gcov: 1 failures in line
counts, 0 in branch percentages, 0 in return percentages, 0 in intermediate
format
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++11 line 22: is #####:should be
1
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++14 gcov: 1 failures in line
counts, 0 in branch percentages, 0 in return percentages, 0 in intermediate
format
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++14 line 22: is #####:should be
1
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++98 gcov: 1 failures in line
counts, 0 in branch percentages, 0 in return percentages, 0 in intermediate
format
FAIL: g++.dg/gcov/pr16855-priority.C -std=gnu++98 line 22: is #####:should be
1
FAIL: g++.dg/gcov/pr16855.C -std=gnu++11 gcov: 1 failures in line counts, 0
in branch percentages, 0 in return percentages, 0 in intermediate format
FAIL: g++.dg/gcov/pr16855.C -std=gnu++11 line 21: is #####:should be 1
FAIL: g++.dg/gcov/pr16855.C -std=gnu++14 gcov: 1 failures in line counts, 0
in branch percentages, 0 in return percentages, 0 in intermediate format
FAIL: g++.dg/gcov/pr16855.C -std=gnu++14 line 21: is #####:should be 1
FAIL: g++.dg/gcov/pr16855.C -std=gnu++98 gcov: 1 failures in line counts, 0
in branch percentages, 0 in return percentages, 0 in intermediate format
FAIL: g++.dg/gcov/pr16855.C -std=gnu++98 line 21: is #####:should be 1
I've finally managed to investigate what's going on and the result may point to
an issue with destructor handling beyond just this testcase.
I've managed to produce a reduced testcase that shows the underlying issue:
$ g++ -c prio2.C
$ gcc -o prio2 prio2.o -lsupc++
(I'm linking with gcc and libsupc++ to avoid having to deal with the libstdc++
destructors during investigation.)
On Solaris 12, the testcase produces
In dtor
In Test::~Test
while on Linux (and on Solaris 11 which lacks __cxa_atexit or Solaris 12 with
-fno-use-cxa-atexit) you get
In Test::~Test
In dtor
On Solaris 12 with -fuse-cxa-atexit (the default):
* Test::~Test() is registered via
.init_array
-> _GLOBAL__sub_I_T1
-> __static_initialization_and_destruction_0(1, 65535)
-> __cxa_atexit(Test::~Test(), &T1, &__dso_handle);
* dtor() is called from
.fini_array
Init/Fini Array Section: .init_array
index value derived-address name
[0] 0x80552e0 0x80552e0 frame_dummy
[1] 0x8055348 0x8055348 _GLOBAL__sub_I_T1
[2] 0x8056b60 0x8056b60 _GLOBAL__sub_I_eh_alloc.cc
Init/Fini Array Section: .fini_array
index value derived-address name
[0] 0x80552b0 0x80552b0 __do_global_dtors_aux
[1] 0x80552f7 0x80552f7 _ZL4dtorv [dtor()]
During execution, here are the relevant atexit and __cxa_atexit calls:
__cxa_atexit(_ZN4TestD2Ev)
#0 0xfe1bd348 in __cxa_atexit () from /lib/libc.so.1
#1 0x08055342 in __static_initialization_and_destruction_0(int, int) ()
#2 0x0805535d in _GLOBAL__sub_I_T1 ()
#3 0xfe6b046b in call_array () from /usr/lib/ld.so.1
#4 0xfe6b0636 in call_init () from /usr/lib/ld.so.1
atexit(atexit_fini)
#0 0xfe1bd327 in atexit () from /lib/libc.so.1
#1 0x080551a3 in __start_crt ()
#2 0x0805514c in _start ()
Here's the order and call stack of both destructors:
dtor() called:
#0 0x080552fd in dtor() ()
#1 0xfe6b046b in call_array () from /usr/lib/ld.so.1
#2 0xfe6b082e in call_fini () from /usr/lib/ld.so.1
#3 0xfe6b0a32 in atexit_fini () from /usr/lib/ld.so.1
#4 0xfe1bd4e5 in _exithandle () from /lib/libc.so.1
#5 0xfe1aefa2 in exit () from /lib/libc.so.1
#6 0x08055171 in _start ()
Test::~Test() called:
#0 0x08055368 in Test::~Test() ()
#1 0xfe1bd4dd in _exithandle () from /lib/libc.so.1
#2 0xfe1aefa2 in exit () from /lib/libc.so.1
#3 0x08055171 in _start ()
So we have this registration order:
__cxa_atexit(Test::~Test())
atexit(atexit_fini)
... and as expected the reverse call order:
atexit_fini
dtor()
Test::~Test()
* On Solaris 11 or Solaris 12 with -fno-use-cxa-atexit:
** Test::~Test() is called like this:
.fini_array
-> _GLOBAL__sub_D_T1
-> __static_initialization_and_destruction_0(0, 65535)
-> Test::~Test(&T1)
** dtor() is called from
.fini_array
Init/Fini Array Section: .fini_array
index value derived-address name
[0] 0x8055290 0x8055290 __do_global_dtors_aux 3.
[1] 0x80552d7 0x80552d7 _ZL4dtorv [dtor()] 2.
[2] 0x8055338 0x8055338 _GLOBAL__sub_D_T1 1.
So both destructors are called via the same mechanism and their relative
order is as expected by the testcase.
* On Linux with -fuse-cxa-atexit (the default):
Code is practically identical to Solaris
Init/Fini Array Section: .init_array
index value derived-address name
[0] 0x8048dd0 0x8048dd0 frame_dummy
[1] 0x8048e32 0x8048e32 _GLOBAL__sub_I_T1
[2] 0x8048c70 0x8048c70 _GLOBAL__sub_I_eh_alloc.cc
Init/Fini Array Section: .fini_array
index value derived-address name
[0] 0x8048da0 0x8048da0 __do_global_dtors_aux
[1] 0x8048de0 0x8048de0 _ZL4dtorv
During execution, I find those __cxa_atexit calls:
__cxa_atexit(_dl_fini)
#0 0xf7deacf0 in __cxa_atexit () from /lib/libc.so.6
#1 0xf7dd111e in __libc_start_main () from /lib/libc.so.6
#2 0x08048d05 in _start ()
__cxa_atexit(_ZN4TestD2Ev)
#0 0xf7deacf0 in __cxa_atexit () from /lib/libc.so.6
#1 0x08048e2c in __static_initialization_and_destruction_0(int, int) ()
#2 0x08048e47 in _GLOBAL__sub_I_T1 ()
#3 0x08054c7b in __libc_csu_init ()
#4 0xf7dd1156 in __libc_start_main () from /lib/libc.so.6
#5 0x08048d05 in _start ()
_dl_fini from glibc elf/dl-fini.c
resulting in the execution order expected by the testcase:
Test::~Test() called:
#0 0x0000000000401074 in Test::~Test() ()
#1 0x00007ffff7834410 in __run_exit_handlers () from /lib64/libc.so.6
#2 0x00007ffff783446a in exit () from /lib64/libc.so.6
#3 0x00007ffff781a408 in __libc_start_main () from /lib64/libc.so.6
#4 0x0000000000400f4a in _start ()
dtor() called:
#0 0x0000000000401006 in dtor() ()
#1 0x00007ffff7de818a in _dl_fini () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7834410 in __run_exit_handlers () from /lib64/libc.so.6
#3 0x00007ffff783446a in exit () from /lib64/libc.so.6
#4 0x00007ffff781a408 in __libc_start_main () from /lib64/libc.so.6
#5 0x0000000000400f4a in _start ()
Initially, I thought the Solaris 12 implementation of __cxa_atexit had gotten
this wrong, but on second thought that's not so clear anymore. I saw that
the original testcases FAIL not only on Solaris 12, but also on Darwin and
FreeBSD, also both targets using __cxa_atexit. I could verify that my reduced
testcase executes on Darwin the same way as on Solaris 12, but don't have
access to a FreeBSD system to check what's going on there.
Now I believe there are three possible causes here:
1. The testcases make unwarranted assumptions about the relative execution
order
of exit handlers from C++ destructors vs. destructors with
__attribute__((destructor)), so just the testcases need to be fixed.
2. 3 out of 4 __cxa_atexit implementations either missed the requirement for
relative ordering of exit handlers registered with __cxa_atexit vs.
.fini_array entires
or got it wrong, with only glibc doing the right thing.
3. The relative ordering in both the original and reduced testcases *is*
required,
but g++ makes unwarranted assumptions about the two different mechanisms
it uses to have them called. In this case, g++ would have to be changed to
e.g. use .fini_array entries for both destructors and
__attribute__((destructor))
functions.
Rainer