Boost logo

Boost :

From: JOAQUIN M. LOPEZ MUÑOZ (joaquin_at_[hidden])
Date: 2008-07-11 11:35:05


_______________________________________
De: boost-bounces_at_[hidden] [boost-bounces_at_[hidden]] En nombre de Chris Newbold [Chris.Newbold_at_[hidden]]
Enviado el: viernes, 11 de julio de 2008 16:25
Para: 'boost_at_[hidden]'
Asunto: Re: [boost] [pool] segfault (fun with static initialization ordering)

[...]

> Right. The way that singleton_default guarantees that instance() is called during
> dynamic initialization is by
[analysis of singleton machinery]

That's it.

> > * Where the problem lies can be found by looking at the usage of
> > singleton_pool by fast_pool_allocator: notice that singleton_pool
> > is used *only* when fast_pool_allocator::allocate or ::deallocate
> > are invoked. So, it is perfectly possible to construct a
> > fast_pool_allocator without that forcing the compiler to
> > construct the underying singleton_pool *yet*. And this is what's
> > happening indeed, the sequence of objects construction we're
> > having is this:
> >
> > 1. owned_base::pool_ begins construction
> > 1.1 call of new pool_lii() inside pool::pool
> > 1.1.1 a fast_pool_allocator is cted inside pool_lii ctor.
> > 1.2 pool_ii ends construction
> > 2. pool_ ends construction
> > 3. the singleton instance associated to singleton_pool<...>is
> > cted before main() because fast_pool_allocator uses it later
> > (singleton guarantee).
>
> I'm not sure I buy this explanation entirely.
>
> owned_base::pool_ is a global object. As described above, so is object_creator.

> The test case consists of a single translation unit, and inside that translation
> unit, the declaration of object_creator precedes that of owned_base::pool_
> (because object_creator is declared by a Boost.Pool header which is included
> before the application-level code which declares owned_base).
>
> Following the fairly clear rules about initialization order for namespace-scoped
> global objects, I would have expected the compiler to construct object_creator
> first (and therefore the pool) before constructing owned_base::pool_.

These precedence rules do not apply to class template static data: quoting
the standard (latest draft at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf),
section 3.6.2:

  "Dynamic initialization of a non-local object with static storage
  duration is either ordered or unordered. Definitions of explicitly
  specialized class template static data members have ordered
  initialization. Other class template static data members (i.e.,
  implicitly or explicitly instantiated specializations) have unordered
  initialization. Other objects defined in namespace scope have ordered
  initialization. Objects with ordered initialization defined within a
  single translation unit shall be initialized in theorder of their
  definitions in the translation unit."

That is, only *ordered* file-scope objects are subject to the precedence
rule you're referring to. Class template static data are not ordered by
definition (except if belonging to a full specialization). So, the sequence
I proposed above is consistent AFAICS.

The following is a case where the precende rule *cannot* be applied
for logical reasons:

  template<typename T>
  struct foo{
    static int x;
  };

  template<typename T>
  int foo<T>::x=T::x;

  struct bar
  {
    static int x;
  };

  int bar::x=666;

  static int x=foo<bar>::x;

You see, foo<T>::x is defined before bar::x yet it can only be
initialized after bar::x has already been constructed. In the original case
we're dealing with there are no dependency constraints like this,
yet the sequence I proposed a post ago is to the best of my knowledge
consistent with the rules of C++ (and we're seemingly observing it in at
least a compiler).

BTW, have you tried the fix I was proposing?

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk