Bug#136707: Proposal: Debian should use symbol versions for libdb2, libdb3, libbdb4
I propose that Debian attach a symbol version to all symbols in the
db2, db3, and db4 libraries and that a distinct version be used for
db2, db3 and db4.
I additionally propose that significant libraries that link against db
be relinked to include the symbol versions. In particual, I propose
that at least libsasl, libnss-db, and libpam be rebuilt. I'm not
actually sure it matters for libpam but it probably couldn't hurt.
I will describe the advantages and disadvantages of this proposal and
then describe the tests I made to confirm these advantages and
disadvantages.
Ben discussed some ideas involving both weak symbols and symbol
versions. I don't think these would be useful because I don't think
that the arguments for weak aliases apply in this case. A weak alias
is useful when you have some symbol that the application may want to
redefine and you want to avoid duplicate symbol warnings. Libc does
this to be pedantically correct with regard to the C spec as I
understand it.
Advantages
1) It works to solve external symbol collisions as defined earlier in
this bug. An application linked against symbol versioned libdb3
will always call the db3 symbols even if an library linked
against a versioned db2 is linked in.
2) It mostly works even if we don't relink the applications. If an
application was linked against an unversioned libdb3 then the
symbols it gets will depend on link order, but any libraries it
calls that have been relinked will work correctly. That is, to
solve our problem, we need to relink all the db versions and
relink any base libraries that use them. We do not need to relink
our all applications that use db.
3) The solution seems likely to work in the long term. We can
continue to make our packages work even if the upstream adopts
symbol versions. Symbol versions can inherit from each other so we
could fix both the upstream and our versions to work.
4) Easy to implement. You create a 4-5 line version script and pass
it in on the ld command line
Disadvantages
1) Symbol versions are somewhat complex to understand
2) Symbol versions only work if you rebuild all the libraries
involved. An unversioned symbol takes precidence over any
versioned symbol . So we are depending on anyone who might
generate a symbol conflicting with DB to version their symbol. We
implicitly also depend on future versions of db to be have
versioned symbols.
3) A solution like Solaris's -Bgroup would really be simpler and have
more contained semantics. Of course the glibc elf interpreter
doesn't support it, so it's not like we could actually use that
solution.
4) Debian binaries will be incompatible at an ABI level with other
distributions. Because Debian binaries will be looking for
versioned symbols, they will give warnings if run on other
distributions. For db2 and db3 this is a non-issue because there
are already ABI compatibility issues. I think willy is looking to
preserve the upstream ABI for db4. If he wants to do that, he
could install two libraries in the libdb4-dev ; one for other
debian packages to link against and one for people who care about
upstream ABI to use.
5) This solution is specific to the glibc elf interpreter. I note
that Solaris and potentially other elf platforms treat versions
differently.
Despite these disadvantages, I believe this proposal is the only
solution that is likely to work.
Acknowledgements
During my exploration of shared libraries, many people have
contributed useful advice, explanations and listened to me rant. I'd
like to thank Ben Collins, Mark Eichin, Ted Ts'o, Nathan Williams.
I'm beginning to believe I'd like to anti-thank the Elf format.
Tests
My set of test cases can be found at
http://www.meepzorp.org/~hartmans/elf-libtest.tar.gz. Note that these
are distributed under a non-free license that forbids redistribution.
I'm doing this because I'd like to keep a handle on them until I write
better documentation. If you have need for the test cases to be under
a free software license, let me know and I can relicense.
The tests consist of a set of functions that call each other. Each
function prints out the name of the library it is in when it is
called.
There is an application called main which calls foo_a, foo_b and
foo_c. Foo_a can be thought of as a routine in libsasl that accesses
db2. foo_b can be thought of as a symbol shared between db2 and db3.
We can ignore foo_c and foo_d for this discussion, they are used to
prove that -Bsymbolic works, but since that doesn't matter for this
proposal we don't care.
There is a library libfoo1 which roughly represents libsasl. It
defines foo_a and links to libfoo2. Libfoo2 represents libdb2 and
defines foo_b.
The library libfoo3 can be thought of as libdb3. It also defines
foo_b.
The application main links to libfoo3 and libfoo1.
The Makefile in the tests builds at least two versions of everything.
IT builds a version that uses symbol versions placed into the
elf-libtest directory and a version that does not use symbols in the
the elf-libtest/noversion directory.
I present the application main_foo1ns as an example of proof that I
have a solution to the problem described in this bug under the
standard of proof I proposed earlier:
* Binutils and libc version:
ii libc6 2.2.5-3 GNU C Library: Shared libraries and
Timezone
ii binutils 2.11.93.0.2-1 The GNU assembler, linker and binary
utiliti
* The symbol foo_b is a symbol shared between libfoo2 and libfoo3
* The application main_foo1ns calls the symbol foo_b desiring the
version in libfoo3
* The library libfoo1 calls foo_b expecting the one from libfoo2
* If the wrong symbol is called the incorrect consequence will be a
diagnostic indicating that a function from the incorrect library is
called.
* The following log demonstrates that with this solution we do not get
the incorrect consequence:
hartmans@industrial-algebra:elf-libtest(1078)> ./main_foo1ns
libfoo1: foo_a
libfoo2: foo_b
libfoo3: foo_b
libfoo1: foo_c
libfoo3: foo_d
* The following log demonstrates that the problem exists if symbol
versions are not used. Note that libfoo3 is used in both cases for
foo_b
hartmans@industrial-algebra:noversion(1080)> ./main_foo1ns
libfoo1: foo_a
libfoo3: foo_b
libfoo3: foo_b
libfoo1: foo_c
libfoo3: foo_d
I also conducted the following other experiments. If you run the
application linked with symbol versions against libraries without
symbol versions, you get a warning. If you have one of your libraries
with versions and one library without, the library without symbol
versions can replace the symbols even in libraries/applications that
were linked against symbol versioned libraries. Applications linked
against unversioned libraries work fine against unversioned libraries,
using link order to determine what symbols are used. If you upgrade
all the libraries to have symbol versions then inter-library
references take advantage of the symbol versions even though the
application was not linked against libraries with symbol versions.
You can repeat these and other pedantic tests on your own.
Reply to: