This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Duplicate data objects in shared libraries


>>>>> "David" == David Abrahams <david.abrahams@rcn.com> writes:

> One thing we didn't discuss in detail was what should happen in case two
> of a library's dependencies are already loaded, each with its own
> definition for some shared symbol S.

i.e.

A.so -> T.so
     -> U.so

B.so -> U.so

?  Here, if T and U both define S, refs in U will resolve to the copy in T,
but refs in B won't, so we get the same problem.  Hmm.

This problem would be solved if T were to link against U, or vice versa, or
if both were linked against a third library which defined S.

The problem is that RTLD_LOCAL really wants a strict delineation of
provider and user; if a DSO uses a symbol from a DSO that it doesn't
depend on, this premise is violated, and users will get confused.

I would further clarify my proposal #6 thus:

7) Resolution of a relocation in a DSO loaded with RTLD_LOCAL only
   considers definitions in the DSO itself and its dependencies.  If a
   strong definition is seen in the normal breadth-first search of these
   DSOs, it is used; otherwise, a weak definition is chosen by depth-first
   search.

Actually, I'd be inclined to adopt the second sentence for all cases, not
just RTLD_LOCAL.  If a library provides a weak definition of something, and
the executable provides a weak definition as well, it makes sense to me to
use the library version.  Doing so would improve the usefulness of
-Wl,--gc-sections (once it works).

Anyway, adopting this proposal, T and U would each use their own
definition, A would use the one from T, and B would use the one from U.  So
the problem would come when trying to, say, throw from U into A.

It's not difficult to imagine this sort of situation arising with
vague-linkage entities that are emitted when needed.  For example: a
library V defines a non-polymorphic class J but doesn't use its RTTI node.
T and U link against V and both throw objects of type J.  A catches the one
thrown in T, but not the one thrown in U.  We would have been fine if the
RTTI node had been emitted in V, but it wasn't needed, so it wasn't
emitted.

I don't see any way to get ld.so to just give us the semantics we want for
this subcase.

If the author of V is aware of this issue, he can avoid it by making sure
the RTTI node for J is emitted in V, either by using #pragma interface or
(if #7 is adopted) by writing a dummy function which refers to typeid(J).
The same thing is true for other static data.

Unfortunately, this is much harder for template libraries, where we can't
anticipate what parameters our templates might be instantiated with.  If V
defines a template K<X> and T and U independently decide to throw a
K<int***>, there isn't much the author of V can do about it.

The author of a template library can adjust their design to avoid relying
on static data members being combined properly.  For instance, an allocator
pool is less effective if it's partitioned, but no less correct.  But there
seems to be nothing anyone can do to fix throwing a K<int***> from U into
A, unless we adjust RTTI in the same way.  In other words, #2.

We can significantly reduce the number of cases where this situation will
cause problems, but can't eliminate them without abandoning our reliance on
pointer comparison.

Jason


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]