GNOME Bugzilla – Bug 348100
Silent ABI breakage
Last modified: 2006-08-02 19:08:24 UTC
Between gnome-vfs-2.15.2 and 2.15.3, several pieces of the public interface of libgnomevfs-2.0 were removed:
2006-07-07 Alexander Larsson <email@example.com>
Move all bonobo mime support functions to libbonobo.
But the library versioning flags at the beginning of configure.in were not updated according to their own comment block. Now we have a shared library with the same soname but with a deficient ABI vs its old version. That causes all progams and libraries that used to work and happened to use those functions to crash due to unresolved symbols when I upgrade my gnome-vfs library.
This was actually on purpose and we were totally aware of it. It was also announced in the NEWS file. The reason was to get rid of bonobo totally. There was only evolution which was still using that and that links directly to libbonobo so that should crash at all. If some app uses bonobo functionality it should explicitly link against it, so I consider that apps broken and they need to be fixed. Anyway since this was on purpose and announced I guess this is a WONTFIX although you are right, we broke ABI (although not silently ;-D)
Is there any app that do crash for you? Is the OSX linker not able to handle that these functions have been moved to libbonobo?
At compile-time, the darwin linker encodes which linked library supplies each symbol. At runtime, dyld looks for each symbol in that library only. If a symbol has since moved from one lib to another, it won't be found even if its new lib was already linked in for other symbols.
The whole purpose of the -version_info flag in Makefile.am (and hence the configure.in logic used to set its parameters) is to indicate when (and how) the public interface for the shared library changes. One effect, when that's done properly, is that libtool automatically changes the install_name (darwin's concept of soname) when those flags are changed to indicate that symbols have been removed. The result is that the new lib won't overwrite the old one (since it has a different install_name) and anything linked against the old one will not break due to missing symbols.
It works on ELF systems where direct linking is not used. We're not gonna bump the soname and break every app on the planet. I'm sorry.
Perhaps you need to go and reread the library versioning section of the libtool manual (assuming you read it in the first place):
Specifically, it tells you to update CURRENT and set AGE to 0 if interfaces were removed. Breaking portability in this case is not necessary.
do you know how many applications, packages, etc would need to be rebuild or updated if the soname for libgnomevfs changed? Note that the symboles have not been dropped but moved somewhere else
It depends on the distribution. Some (most?) distributions would keep the old library around to satisfy these packages
If you make changes to a library, you should follow libtool's versioning rules to be portable (there may also be other rules that are just as likely to maintain portability, but gnome uses libtool, so...). These are things that should have been thought about prior to making the change, and should never have been done for such a minor version bump.
I see 3 ways to resolve this issue (not that I've looked at the code, don't you hate that, sorry)
Update the package properly and make a new release. Forcing either a rebuild or the distribution keeping the old library.
Revert the patch and make a new release.
Make the symbols weak in libgnome-vfs with an implementation that looks up the symbols in libbonobo using dlsym(RTLD_NEXT,...)
Of the 3, I think 2 is the easiest. Leave major changes for major releases. But I'm quite confident that (4) will be chosen - Do nothing, leave it broken. I can guess that because it's marked "WONTFIX" :-)
Option 4: have the old code be optionally included under the control of an --enable-binary-compatibility configure flag.
"These are things that should have been thought about prior to making the change"
Those things have been thought prior to the change, read the comments from Christian and Alexander for the rational about it
"If some app uses bonobo functionality it should explicitly link against it, so I consider that apps broken and they need to be fixed. [...] Is the OSX linker not able to handle that these functions have been moved to libbonobo?"
The problem comes not from being linked against libbonobo (which it should already be) but instead from a feature of Apple's Mach-O implementation. The OSX linker since 10.2 has preferred "two-level" libraries, in which the possibility of symbol-conflicts and link-time ambiguities between libraries is resolved by encoding (at link time) which library a given symbol comes from and always resolving it through that library at run-time. Darwin isn't the only OS with this behavior; it's similar to the "-B direct" option on Solaris, HP-UX, and IRIX. Once an executable or library is created two level namespace the dynamic linker will only look for symbols in the library that had them at static link time. It is the default because it improves performance, and solves potential ambiguities in the way decisions made to find the "correct" symbol to use at runtime when code changes over time.
The only way to get around the link-time encoding of a dependent symbol's rpath is to explicitly force the library to be linked as "flat namespace" which the GNOME libraries are not, by default.
A lot of the confusion relating to portability of shared libraries and modules to non-ELF platforms comes from the concept that in Mach-O, a shared library (link-time code) and a module or loadable bundle (run-time loaded code) are totally different things, and are treated very differently. This causes subtle mismatches in the way people assume things to work. Libtool is designed to help developers work around these issues, and has their versioning rules for a good reason. If you remove an interface, the version numbers should be changed, or else you're not portable. Perhaps it happens to work on ELF, but ELF is not UNIX, and you're cutting out Mach-O (and most likely a.out, as it tends to have similar issues) at the very least by following only ELF conventions.
"If some app uses bonobo functionality it should explicitly link against it [...] Is the OSX linker not able to handle that these functions have been moved to libbonobo?"
I have a program that was compiled against gnomevfs, and according to 'otool -L' (similar to 'ldd'), it dynamically links:
/sw/lib/libgnomevfs-2.0.dylib (compatibility version 1001.0.0, current version 1001.1.0)
/sw/lib/libORBitCosNaming-2.0.dylib (compatibility version 2.0.0, current version 2.0.0)
/sw/lib/libpopt.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/sw/lib/libgobject-2.0.0.dylib (compatibility version 801.0.0, current version 801.6.0)
/sw/lib/libxml2.2.dylib (compatibility version 9.0.0, current version 9.26.0)
/sw/lib/libbonobo-2.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/sw/lib/libgconf-2.4.dylib (compatibility version 6.0.0, current version 6.0.0)
/sw/lib/libbonobo-activation.4.dylib (compatibility version 5.0.0, current version 5.0.0)
/sw/lib/libORBit-2.0.dylib (compatibility version 2.0.0, current version 2.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 71.1.4)
/sw/lib/libgmodule-2.0.0.dylib (compatibility version 801.0.0, current version 801.6.0)
/sw/lib/libgthread-2.0.0.dylib (compatibility version 801.0.0, current version 801.6.0)
/sw/lib/libglib-2.0.0.dylib (compatibility version 801.0.0, current version 801.6.0)
/sw/lib/libintl.3.dylib (compatibility version 8.0.0, current version 8.3.0)
/sw/lib/libiconv.2.dylib (compatibility version 6.0.0, current version 6.0.0)
And according to 'nm', the only place those symbols are defined is in /sw/lib/libgnomevfs-2.0.dylib(gnome-vfs-mime-handlers.o). Even if my dynamic loader *could* fall back to other libraries to resolve a symbol, it wouldn't help, because there's nothing on which to fall back that supplies the symbol.
A relatively easy to implement solution would be a combination of those proposed so far: a --with-legacy-interface configure flag that, if passed, would implement those missing functions using dlopen/dlsym. The default would be the status quo--symbols are omitted and bonobo (old or new) is not accessed in any way at all.
None of the old implementation of the functions would need to be re-added into gnomevfs itself. If the flag were ser, just a ~10-line wrapper for each of the 3 symbols, plus a configure pkgconfig check and flags for bonobo-activation >= 2.15.
Any interest in patches to do this?