https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44779
Martin Liška <marxin at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|WAITING |RESOLVED CC| |marxin at gcc dot gnu.org Resolution|--- |INVALID --- Comment #6 from Martin Liška <marxin at gcc dot gnu.org> --- (In reply to Jay Vaughan from comment #0) > I am developing a software system which has the requirement (as it is > safety-critical), that we report full coverage of our modules as part of the > validation process. > > One aspect of this software system is the inclusion of a library - lets call > it libguardian - which is wrapped around all applications being run on our > custom system, using LD_PRELOAD. The purpose of libguardian is to obtain > valid conditions for continued launch prior to the execution of main() by > the runtime in the wrapped application. To this end, libguardian defines a > constructor and destructor pair of functions that obtain the valid > conditions required for continued launch, and clean up/report on exit of the > application. > > This libguardian, and associated applications, works perfectly fine. > However, it is not possible to capture coverage information for these > functions due to limits in gcov. > > The constructor/destructor methods are defined thus: > > > #define GUARDIAN_CONSTRUCTOR_DESTRUCTOR_PRIORITY 65535 > /* NOTE: this priority can also be 101! */ > > void guardian_constructor(void) __attribute__ > ((constructor(GUARDIAN_CONSTRUCTOR_DESTRUCTOR_PRIORITY))); > > void guardian_destructor(void) __attribute__ > ((destructor(GUARDIAN_CONSTRUCTOR_DESTRUCTOR_PRIORITY))); > > > If the guardian_constructor() finds conditions unsavory for continued > execution in our environment, it exit()'s immediately. In this circumstance, > coverage is lost (or not provided) by gcov's atexit/destructor methods, as > it appears that *priority* of known constructors is not accounted for in the > gcov library, nor is there an atexit() handler that can adequately sort > these priorities. Well, there are two scenarios that happen for your test-case: 1) guardian_constructor exits: as the function is called via LD_PRELOAD, libgcov is not yet registered and cannot produce any *.gcda files. It's unrelated to priorities of dtors/atexit handlers 2) _SHOULD_CONSTRUCTOR_DIE_ is undefined: all works fine except guardian_exiter: LD_PRELOAD=./testlib.so ./testapp ++++++ GUARDIAN CONSTRUCTOR STAGE: [15226] This is a number between 1 and 10: 1 This is a number between 1 and 10: 2 This is a number between 1 and 10: 3 This is a number between 1 and 10: 4 This is a number between 1 and 10: 5 This is a number between 1 and 10: 6 This is a number between 1 and 10: 7 This is a number between 1 and 10: 8 This is a number between 1 and 10: 9 This is a number between 1 and 10: 10 ********************************** gcov init is called gcov init is called ^^ That was the constructor ^^ This is main() in the testapp() By now, the testlib should have reported its own progress in counting 1 to 10. Next comes the destructor ::: gcov_exit is called ------ GUARDIAN DESTRUCTOR STAGE: ********************************** gcov_exit is called !!!!!! GUARDIAN EXIT HANDLER REACHED !!!!!! gcov testlib.c File 'testlib.c' Lines executed:78.57% of 14 Creating 'testlib.c.gcov' gcov testapp.c File 'testapp.c' Lines executed:100.00% of 3 Creating 'testapp.c.gcov' As you can see, I added dumping of gcov_init/gcov_exit. The only functions which is not seen by coverage is: #####: 16:static void guardian_exiter(void) -: 17:{ #####: 18: fprintf(stderr, "!!!!!! GUARDIAN EXIT HANDLER REACHED !!!!!!\n"); #####: 19:} That's kind of expected behavior because atexit handlers are executed in reverse order to how they were registered. I would recommend to not utilize atexit handler and do the necessary work in guardian_destructor. Due to aforementioned explanation, I'm closing the PR as invalid.