[libc++] [PATCH] global object initialization bug

Howard Hinnant hhinnant at apple.com
Sun Mar 31 08:36:36 PDT 2013


On Mar 31, 2013, at 1:39 AM, WenHan Gu (谷汶翰) <wenhan.gu at gmail.com> wrote:

> Yes, thanks for your review.
> 
> However, in program P uses different dynamic libraries A and B,
> if A's global objects init by B's global objects, It might have the same problem even on __APPLE__ right?

The linker orders inits "from bottom up", where the direction is defined by what links to what.  For dylib A to use std::cout, it must link to libc++.  This causes the linker to run libc++'s global inits prior to those in dylib A.

> 
> Actually, Someone told me programmer should not rely on this idiom.
> He said, if the program uses global object init depending on another component's global object init.
> This program should be considered wrong.
> 
> I've no idea whether I should submit this patch,
> It seems it is a tricky that only GNU libstdc++ has.

The idiom gcc has, and that you suggest, is what is recommended by the standard.  The libc++ implementation of it, combined with the linker behavior on OS X / iOS, is a conforming optimization of that idiom.

Howard

> 
> 
> 2013/3/30 Howard Hinnant <hhinnant at apple.com>
> On Mar 5, 2013, at 2:35 AM, WenHan Gu (谷汶翰) <wenhan.gu at gmail.com> wrote:
> 
> > Hi all,
> >
> > If I use cerr/cout... before main function, it may potentially cause use-before-init before this patch.
> >
> > This is a tiny patch, but important to guarantee init-before-use.
> > Please review it. Thanks!!
> >
> >
> > ===
> >
> > Long explanation:
> >
> > std::cout, cerr, ... are global objects that should be initialized before use. However, C++ does not guarantee an order of initialization between static objects in different translation units.
> > One basic idiom is that declares a static object that gets created in every translation unit that includes <iostream>. This object has a static constructor and destructor that initializes and destroys the global iostream objects before they could possibly be used in the file.
> > In GNU libstdc++, it is at
> > <libstdc++>/include/std/iostream: static ios_base::Init __ioinit;
> > but in libcxx, it is at src/iostream.cpp, i.e., it only guarantee initialized when entering main function. If we use them before main, it may cause undefined behavior since it is a use-before-init bug.
> >
> > Thanks!
> 
> Sorry for the long delay in reviewing this patch.
> 
> If this patch is to be committed, it will have to be #ifdef'd out on __APPLE__.  On Apple platforms we have an additional guarantee: if A links against B, B's initializer will be run before A's.
> 
> I.e. if you link to libc++.dylib, then cout et al. are guaranteed to be constructed before your initializers run.
> 
> Use of this guarantee is a deliberate design decision.  It greatly reduces the number of global constructors (-Wglobal-constructors) in a program.  This in turn can increase launch time performance.
> 
> Howard
> 
> 
> 
> 
> -- 
> Best Regards,
> WenHan Gu (Nowar)





More information about the cfe-commits mailing list