* Method to specify initialization order across translation units? @ 2015-08-05 16:47 Jeffrey Walton 2015-08-05 20:50 ` Andrew Haley 0 siblings, 1 reply; 5+ messages in thread From: Jeffrey Walton @ 2015-08-05 16:47 UTC (permalink / raw) To: gcc-help I'm catching an intermittent failure due to initialization order across translation units. The code is for a C++ library that offers both a static archive and a shared object. My first thought was to provide an accessor function and make the global a static local. That did not work because the order of construction and destruction was not right. It resulted in a crash in a destructor because an object disappeared too soon. My second thought was init_priotrity and __attribute__ (constructor) (and friends), but I know from experience that does not work across translation units. My third though was a linker script, and then I came across "Replace .ctors/.dtors with .init_array/.fini_array on targets supporting them" (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770#c96) and "collect2 breaks link order control" (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53068). If I am reading the reports correctly, then a linker script is not the tool for the job. We also thought about adding a global.cpp file, but we are not sure it will meet goals because of third party programs, the static archive, and the interactions during linking. The static archive seems to be the trickiest case because of the interaction with third party programs. The shared object seems to be an easier problem because its fully linked, and does not interact with program linking. (Open question: does LTO affect this?). Are there any methods to specify initialization order across translation units? If so, what is it (or are they)? ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Method to specify initialization order across translation units? 2015-08-05 16:47 Method to specify initialization order across translation units? Jeffrey Walton @ 2015-08-05 20:50 ` Andrew Haley 2015-08-12 21:48 ` Jeffrey Walton 0 siblings, 1 reply; 5+ messages in thread From: Andrew Haley @ 2015-08-05 20:50 UTC (permalink / raw) To: noloader, gcc-help On 05/08/15 17:47, Jeffrey Walton wrote: > I'm catching an intermittent failure due to initialization order > across translation units. The code is for a C++ library that offers > both a static archive and a shared object. > > My first thought was to provide an accessor function and make the > global a static local. That did not work because the order of > construction and destruction was not right. It resulted in a crash in > a destructor because an object disappeared too soon. My second thought > was init_priotrity and __attribute__ (constructor) (and friends), but > I know from experience that does not work across translation units. > > My third though was a linker script, and then I came across "Replace > .ctors/.dtors with .init_array/.fini_array on targets supporting them" > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770#c96) and "collect2 > breaks link order control" > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53068). If I am reading > the reports correctly, then a linker script is not the tool for the > job. > > We also thought about adding a global.cpp file, but we are not sure it > will meet goals because of third party programs, the static archive, > and the interactions during linking. > > The static archive seems to be the trickiest case because of the > interaction with third party programs. The shared object seems to be > an easier problem because its fully linked, and does not interact with > program linking. (Open question: does LTO affect this?). > > Are there any methods to specify initialization order across > translation units? If so, what is it (or are they)? init_priority (priority) In Standard C++, objects defined at namespace scope are guaranteed to be initialized in an order in strict accordance with that of their definitions in a given translation unit. No guarantee is made for initializations across translation units. However, GNU C++ allows users to control the order of initialization of objects defined at namespace scope with the init_priority attribute by specifying a relative priority, a constant integral expression currently bounded between 101 and 65535 inclusive. Lower numbers indicate a higher priority. In the following example, A would normally be created before B, but the init_priority attribute reverses that order: Some_Class A __attribute__ ((init_priority (2000))); Some_Class B __attribute__ ((init_priority (543))); Note that the particular values of priority do not matter; only their relative ordering. Andrew. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Method to specify initialization order across translation units? 2015-08-05 20:50 ` Andrew Haley @ 2015-08-12 21:48 ` Jeffrey Walton 2015-08-13 8:05 ` Jonathan Wakely 0 siblings, 1 reply; 5+ messages in thread From: Jeffrey Walton @ 2015-08-12 21:48 UTC (permalink / raw) To: Andrew Haley; +Cc: gcc-help >> Are there any methods to specify initialization order across >> translation units? If so, what is it (or are they)? > > init_priority (priority) > > In Standard C++, objects defined at namespace scope are guaranteed > to be initialized in an order in strict accordance with that of their > definitions in a given translation unit. No guarantee is made for > initializations across translation units. However, GNU C++ allows > users to control the order of initialization of objects defined at > namespace scope with the init_priority attribute by specifying a > relative priority, a constant integral expression currently bounded > between 101 and 65535 inclusive. Lower numbers indicate a higher > priority. > > In the following example, A would normally be created before B, > but the init_priority attribute reverses that order: > > Some_Class A __attribute__ ((init_priority (2000))); > Some_Class B __attribute__ ((init_priority (543))); > > Note that the particular values of priority do not matter; only > their relative ordering. Thanks again Andrew. Forgive my ignorance... what init_priority should I use? I selected a base priority of 250, and then specified the order of 5 file scope objects. The objects were 3 std::strings and 2 C++ class objects. That's the extent of file scope C++ objects in this library. My thinking was 250 will give the standard runtime and other required libraries to initialize first. Then, initialize the five objects of interest. These are objects which have implicit dependencies that's we can't seem to express in C++ Then initialize "don't care" values, which don't appear to have a dependency with special needs. After the initialization of the 5 C++ objects, I specified 1 [non-class] function as a constructor with a priority of 300. Combined, it resulted in the issue with the POD type initialization (like a bool is no longer initialized when used), and issues with libstdc++. So 250/300 is not the magic number... Thanks in advance. ==16604== Conditional jump or move depends on uninitialised value(s) ==16604== at 0x4F37F4E: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.21) ==16604== by 0x4F381FF: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, bool) const (in /usr/lib64/libstdc++.so.6.0.21) ==16604== by 0x4F44BDA: std::ostream& std::ostream::_M_insert<bool>(bool) (in /usr/lib64/libstdc++.so.6.0.21) ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Method to specify initialization order across translation units? 2015-08-12 21:48 ` Jeffrey Walton @ 2015-08-13 8:05 ` Jonathan Wakely 2015-08-14 0:00 ` Jeffrey Walton 0 siblings, 1 reply; 5+ messages in thread From: Jonathan Wakely @ 2015-08-13 8:05 UTC (permalink / raw) To: Jeffrey Walton; +Cc: Andrew Haley, gcc-help On 12 August 2015 at 22:48, Jeffrey Walton wrote: > > Forgive my ignorance... what init_priority should I use? It doesn't matter, only the relative values matter. > I selected a > base priority of 250, and then specified the order of 5 file scope > objects. The objects were 3 std::strings and 2 C++ class objects. > That's the extent of file scope C++ objects in this library. > > My thinking was 250 will give the standard runtime and other required > libraries to initialize first. Then, initialize the five objects of > interest. These are objects which have implicit dependencies that's we > can't seem to express in C++ Then initialize "don't care" values, > which don't appear to have a dependency with special needs. > > After the initialization of the 5 C++ objects, I specified 1 > [non-class] function as a constructor with a priority of 300. > > Combined, it resulted in the issue with the POD type initialization > (like a bool is no longer initialized when used), and issues with > libstdc++. So 250/300 is not the magic number... Of course not, if there was a magic number then everything would be initialized with that priority by default. Did you give the bool an init_priority? You need to work out which globals depend on each other and ensure that each one is initialized before anything that depends on it. If some of them depend on the bool then you need to ensure the bool is initialized before the objects that depend on it. You could solve the problem portably by just putting all your globals in one translation unit and ordering their declarations, so you don't need to use init_priority at all. There's an open bug report about iostreams not being usable from constructors of objects with init_priority, because using init_priority can make your object get initialized before the iostreams have been set up. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Method to specify initialization order across translation units? 2015-08-13 8:05 ` Jonathan Wakely @ 2015-08-14 0:00 ` Jeffrey Walton 0 siblings, 0 replies; 5+ messages in thread From: Jeffrey Walton @ 2015-08-14 0:00 UTC (permalink / raw) To: Jonathan Wakely; +Cc: gcc-help >> Combined, it resulted in the issue with the POD type initialization >> (like a bool is no longer initialized when used), and issues with >> libstdc++. So 250/300 is not the magic number... > > Of course not, if there was a magic number then everything would be > initialized with that priority by default. > > Did you give the bool an init_priority? > > You need to work out which globals depend on each other and ensure > that each one is initialized before anything that depends on it. If > some of them depend on the bool then you need to ensure the bool is > initialized before the objects that depend on it. OK, the bool issue turned out to be a MS assembly block (consumed by GCC) that lacked volatile. It was apparently removed by GCC, so it caused a cascade of problems under Valgrind. The block was essentially a one-liner that called CPUID. The program is now clean under Valgrind and the Sanitizers (both GCC and Clang). Its also clean under -Wall -Wextra. But the crash persists under Cygwin at -O3 (Cygwin at -O2 is OK, and MinGW is OK). I think I'm at the point of diminishing returns for a less frequently used platform. I think I'm going to cut my loses now. Thanks for the help. Jeff ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-08-14 0:00 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-08-05 16:47 Method to specify initialization order across translation units? Jeffrey Walton 2015-08-05 20:50 ` Andrew Haley 2015-08-12 21:48 ` Jeffrey Walton 2015-08-13 8:05 ` Jonathan Wakely 2015-08-14 0:00 ` Jeffrey Walton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).