This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc 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]

[Bug dynamic-link/12977] glibc dynamic linker behaves unpredictable when using base version


https://sourceware.org/bugzilla/show_bug.cgi?id=12977

Diego Barrios Romero <eldruin at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |eldruin at gmail dot com

--- Comment #3 from Diego Barrios Romero <eldruin at gmail dot com> ---
Created attachment 9761
  --> https://sourceware.org/bugzilla/attachment.cgi?id=9761&action=edit
Symbol overwrite example

I found a different manifestation of this unpredictability w.r.t. the base
version of symbols.

I have attached an example program setup in which symbols are overwritten by
the base version even though a library specifies that it needs a specific
version.

The example contains two libraries (A and B) that offer the symbol f.
A does not define any version, but B does define it in version B_1.0.
Then there are two libraries (AU and BU) that use these libraries, each using
only one of them, and they offer the fAU and fBU functions.
Then a program 'p' links both libraries AU and BU (See makefile for more
information).

At run time, the symbol f that is requested by BU with version B_1.0 gets
matched with the base version one provided by library A. Even though the symbol
with the adequate version is also available, the base version is returned.

Here are the relevant symbol entries when doing objdump -TC
libA.so:
  0000000000000705 g    DF .text        0000000000000012  Base        f

libB.so:
  0000000000000765 g    DF .text        0000000000000012  B_1.0       f

libAU.so:
  0000000000000000      DF *UND*        0000000000000000              f

libBU.so:
  0000000000000000      DF *UND*        0000000000000000  B_1.0       f

It also happens the other way around, the f base version requested by AU is
overwritten by f@@B_1.0 if changing the link order (-lBU -lAU).
While this latter behaviour is also unexpected, matching the base version to a
symbol containing a specific version sounds definitely unexpected to me.

If you compile and run the program 'p', you should see something like this:
  AU::fAU()
  A::fA()
  A::f()
  A::f()
  BU::fBU()
  B::fB()
  A::f()
  A::f()

If you add version information to library A (uncomment commented line in the
makefile), you will see that the symbols get matched as expected and the
program reports:
  AU::fAU()
  A::fA()
  A::f()
  A::f()
  BU::fBU()
  B::fB()
  B::f()
  B::f()

I was able to reproduce this on ubuntu 14.04 (eglibc 2.19) and on ubuntu 16.04
(glibc 2.23).

I also had a look at the source code and think that the check_match subroutine
in elf/dl-lookup.c behaves unexpectedly.

To my outsider eyes, it sounded like the 'else' case below could be at fault.
It looks like it would return the default version if the version information
does not match but a non-hidden default version exists. This would of course
not be the case depending on "who-is-who" in these variables, but I could not
get any further.

        const ElfW(Half) *verstab = map->l_versyms;
        if (version != NULL)
          {
            if (__builtin_expect (verstab == NULL, 0))
              {
                /*...*/
              }
            else
              {
                /* We can match the version information or use the
                   default one if it is not hidden.  */
                ElfW(Half) ndx = verstab[symidx] & 0x7fff;
                if ((map->l_versions[ndx].hash != version->hash
                     || strcmp (map->l_versions[ndx].name, version->name))
                    && (version->hidden || map->l_versions[ndx].hash
                        || (verstab[symidx] & 0x8000)))
                  /* It's not the version we want.  */
                  return NULL;
              }
         /*...*/

I tried adding a version_matched flag and keep looking in other 'scopes' (see
for loop in function _dl_lookup_symbol_x) for a better match instead of
returning the first one but it did not immediately work so I decided to report
it here instead.

Does this example help you reproduce this?

-- 
You are receiving this mail because:
You are on the CC list for the bug.

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