The std::string<T> class template depends on having only one 
__null_string_ref_rep<T> in the entire program.

The std::string template is pre-instantiated on char and wchar_t, in 
which case the only __null_string object is already in libCstd, and does 
not get replicated.

I think the problem comes from creating a std::string on another type, 
unsigned int in your case. You need to take steps to ensure only one 
copy of  __null_string_ref_rep<T> exists, for any T other than char or 
wchar_t.

You can do that by building libraries in hierarchical order, bottom up, 
and using the -instlib option to prevent instances of the same template 
from being generated in more than one library. Here is how:

1. Determine the (partial) ordering of library dependencies. There must 
be no cycle in the dependency graph.

2. Build the lowest-level library first, the one which depends on no 
other project library. Call it libA.so.

3. Build the next-higher library, call it libB, which depends on libA. 
For each CC command that creates a .o file that will go into libB, add 
the option
     -instlib=/path/to/libA.so

4. Build the next-higher library, libC.so. For each CC command that 
creates a .o file that will go into libC, add the options
    -instlib=/path/to/libA.so -instlib=/path/to/libB.so
(assuming libC depends on both libA and libB).

You need an -instlib option only for a library on which the current 
library depends (directly or transitively).

You can read more about the -instlib option in the C++ Users Guide 
Appendix on command-line options. The option causes the the compiler to 
scan the named library for template instances (and inline functions 
generated out of line), and omit generating them in the current .o file. 
In my example, libB will contain no template instance that occurs in 
libA, and libC will contain no template instance that occurs in libA or 
libB.

We are planning to add the capability to the compiler and Solaris linker 
to specify that an object must be a singleton, which will eliminate the 
need for this elaborate build process just to fix the _null_string 
problem. We do not have a projected date for the new option. You might 
still need to use -instlib to eliminate other circular references, however.

---
Steve Clamage, stephen.clamage at sun.com

On 6/22/2007 8:32 PM, Yong Sun wrote:
> Hi, Steve,
> 
> Thank you very much!
> 
> In my case (the dltest.tar), when the main program call dlopen 
> ("libtest.so"), it resolves the dependencies, then adds libbase.so in 
> the initialization sequence ahead of libtest.so (the order is reversed). 
> And we all knew that the static constructors in a shared library are in 
> the .init routine.
> 
> While it's trying to initialize the static object "bar" in libbase.so, 
> it finds there is a symbol "xxx::__null_string_ref_rep<xxx>" (introduced 
> by std::basic_string<unsigned int>), then looks up this symbol in loaded 
> libraries. Firstly, it looks up the symbol in main program, then in 
> libc.so, then finds matched one in libtest.so, and stops to move on 
> (actually, libbase.so also has this symbol). Then it tries to initialize 
> libtest.so, and initializes the static object "foo". Unfortunately, the 
> constructor of Foo calls a external function in libbase, and this 
> function accesses the static instance "bar", which is not initialized 
> yet (the "buf" is not allocated).
> 
> So the main program cores.
> 
> I am not sure, maybe the ld.so should first lookup the symbol in the 
> current initializing shared library, i.e., libbase.so?
> 
> Regards,
> 
> Steve Clamage wrote:
>> We have a deliberate, although possibly mis-guided, interaction 
>> between libCrun and libCstd initialization. To ensure that C++ 
>> iostreams are initialized soon enough, CCrti (program startup code for 
>> C++) calls a routine in libCun that has a table of initialization 
>> routines that are done first. The only entry in the table currently is 
>> the one to initialize iostreams in libCstd. (It uses a weak symbol 
>> definition for the target, so if libCstd is not linked, nothing happens.)
>>
>> If a user program has a proper dependency on libCstd, this bouncing 
>> between libCrun and libCstd, and their respective initializations, 
>> should finish before any user library starts its initialization. At 
>> least, that's how it seems to me.
>>
>> Do we have a case where a user program has a dependency on libCstd, 
>> but sill mixes its initialization with that of libCstd? If so, I'd 
>> like to know how that happened, and what we could do to ensure that 
>> doesn't happen.
>>
>> We are now looking again at the iostream issue. I think we can arrange 
>> for libCrun to initialize itself without any reference to libCstd, and 
>> for libCstd to ensure that iostreams are initialized first.
>>
>> If we make that change, programs that now use libCstd but have no 
>> dependency on it, might stop working. I consider such a situation to 
>> be user error (correct me if I am wrong), in which case the change 
>> doesn't bother me.
>>
>> ---
>> Steve Clamage, stephen.clamage at sun.com
>>
>>
>> On 06/21/07 17:45, Rod Evans wrote:
>>> Yong Sun wrote:
>>>> Hi, Rod,
>>>>
>>>> I finally isolated the problem to very simple example C/C++ source 
>>>> files, as attached. If you have interests, you could extract the tar 
>>>> file, and run gmake. Then you could see, test would core, while 
>>>> test2 would succeed.
>>>
>>> Someone from C++ land is going to have to unravel this.
>>>
>>> There are multiple instances of the same symbol in different libraries,
>>> cyclic dependencies, and .init code that jumps all over the place.
>>>
>>> Set LD_DEBUG=.init and we start seeing:
>>>
>>> 04973: 1: calling .init (from sorted order): /usr/lib/libCrun.so.1
>>> 04973: 1:
>>> 04973: 1: calling .init (dynamically triggered): /usr/lib/libCstd.so.1
>>> 04973: 1:
>>> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not 
>>> completed
>>> 04973: 1:
>>> 04973: 1: calling .init (dynamically triggered): ./libtest.so
>>> 04973: 1:
>>> 04973: 1: calling .init (dynamically triggered): 
>>> /home/rie/dltest/libbase.so
>>> 04973: 1:
>>> 04973: 1: warning: calling ./libtest.so whose init has not completed
>>> 04973: 1:
>>> 04973: 1: warning: calling ./libtest.so whose init has not completed
>>> 04973: 1:
>>> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not 
>>> completed
>>> 04973: 1:
>>> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not 
>>> completed
>>>
>>> Now I can't tell you that these indicate problems or not, as there is no
>>> way to determine whether a reference to another object requires that 
>>> object
>>> to have completed its .init for the reference to be valid.  Meaning, if
>>> data is updated by a .init, and that data is referenced before the .init
>>> has completed, are you in trouble?
>>>
>>> If you expand a little with init,bindings:
>>>
>>> 04948: 1: calling .init (from sorted order): /usr/lib/libCrun.so.1
>>> ......
>>> 04948: 1: binding file=/usr/lib/libCrun.so.1 to 
>>> file=/usr/lib/libCstd.so.1: \
>>>   symbol `__SUNW_force_load_of_inits'
>>> 04948: 1:
>>> 04948: 1: calling .init (dynamically triggered): /usr/lib/libCstd.so.1
>>>
>>> Hmmm, __SUNW_force_load_of_inits - that looks scary.
>>>
>>> 04948: 1: binding file=/usr/lib/libCstd.so.1 to 
>>> file=/usr/lib/libCrun.so.1: \
>>>   symbol `__1cG__CrunSregister_exit_code6FpG_v_v_
>>> 04948: 1:
>>> 04948: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not 
>>> completed
>>>
>>> So, you have libCruns .init calling libCstd.so.1, and libCstds .init 
>>> calling
>>> libCrun.so.1
>>>
>>> The scenario continues through your other objects.
>>>
>>> The runtime linker is simply jumping from object to object as directed,
>>> and trying frantically to fire .init's before an object is called.  When
>>> cyclic dependencies exist, you can't programaticaly determine a 
>>> "correct"
>>> order, so the dynamic firing attempts to compensate - and from 
>>> experience
>>> we know that without this "compensation" a whole mess of applications
>>> would already be falling over.
>>>
>>> I'll stick by my concluding remarks from
>>>
>>>    http://blogs.sun.com/rie/entry/init_and_fini_processing_who
>>>
>>> and let's see if someone from C++ can enlighten us some more.
>>>
> 

Reply via email to