public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* 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).