4

Suppose I have a dynamic library that exports three functions:

void lib_function(void);
void lib_extra_function(void);
int  lib_runtime_version(int v);

And lib_extra_function was added in version 2 of the library.

If an application that uses lib_extra_function is built on a system with library version 2 installed, and then run on a system that provides only version 1, "symbol lookup error: ./main: undefined symbol: lib_extra_function" dynamic linker error is raised once lib_extra_function is called.

However, if application tries to use version information provided by library and call lib_extra_function conditionally, no error is raised, even though lib_extra_function is still undefined.

voif f()
{
    if(lib_runtime_version() >= 2) {
        lib_extra_function();
    } else {
        // try some workaround
    }
}

Now, is this behavior mandated by any standard? If not, is it specific to Linux? How do linkers in other systems (OSX, BSD) behave?

jww
  • 97,681
  • 90
  • 411
  • 885
  • "If an application that uses `lib_extra_function` is compiled against version 2 is run on a system that provides only version 1...." - I don't understand it, everything compiled and linked, but when you run you program dynamic linker gives you error ? Or it is linkage error occurred during build ? – Dabo Apr 27 '14 at 09:24
  • @Dabo I mean a situation when application is built with newer version of library, but run with older version. Linker error is raised at runtime. I clarified my question a bit. – el.pescado - нет войне Apr 27 '14 at 09:55
  • If it was already compiled with version 2, how it could raise an error in the system with version 1 if no linking is done ? I don't think any loader on any OS checks the code to see if all functions are actually defined.. – perencia Apr 27 '14 at 09:59
  • I assume using a dynamic library. In that case, loader (`ld-linux.so` in case of Linux) takes care of resolving symbols. – el.pescado - нет войне Apr 27 '14 at 10:05
  • @el.pescado If you link during the build stage against new lib everything found and everything is ok, later in runtime dynamic linker looks for proper shared library (the bug you describe here is classical for shared libs, so i assume this is the case) and it founds another version, the previos one, loads it and your code crash and burn as required function ( symbol ) not there. – Dabo Apr 27 '14 at 10:07
  • @el.pescado I understand your concern now. When you check in runtime the version of your library, and don't call `lib_extra_function` in case `version < 2` why would it fail ? You checked the version, you saw that current version does not support `lib_extra_function`, you are not trying to jump to symbol that does not exist. Shared functionality does not reside in your code, in your code you only have the logic to jump to needed shared address, as long as you don't enable it everything is ok in your case. – Dabo Apr 27 '14 at 10:21
  • Dabo: That's what I am asking: can I depend on that behavior? For eample, if I load a shared library using `dlopen` and I pass `RTLD_NOW` flag, all symbols are resolved immediately. The same is when I run my program with `LD_BIND_NOW` environment variable set - Program is not loaded even though undefined symbols are not called at all. – el.pescado - нет войне Apr 27 '14 at 10:31
  • From docs `RTLD_NOW If this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty string, all undefined symbols in the library are resolved before dlopen() returns. **If this cannot be done, an error is returned.**` So i guess with `RTLD_NOW` you won't crash immediately but `dlerror()` will return you an error string. Actually need to check this precise scenario – Dabo Apr 27 '14 at 10:56

1 Answers1

3

Now, is this behavior mandated by any standard?

No.

If not, is it specific to Linux?

No. It's a behavior that is supported by systems that do lazy runtime symbol resolution.

In general you should avoid doing this:

if(lib_runtime_version() >= 2) {
    lib_extra_function();

for a few reasons:

  • it will not work at all on systems that do eager symbol resolutions,
  • it will explode if end-user sets LD_BIND_NOW (which is special case of above), and
  • it violates the DRY principle.

Instead, if a function is optionally provided, use dlsym to find out whether it is available:

p_extra = dlsym(..., "lib_extra_function");
if (p_extra != NULL) {
    ....
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • The question is, is it reasonable to expect user to have `LD_BIND_ALL` set? – el.pescado - нет войне Apr 29 '14 at 20:36
  • @el.pescado Users often set LD_BIND_NOW when they are trying to debug something, so yes, it is reasonable to expect this to be set. Some users also set LD_BIND_NOW to avoid "surprise unresolved symbols at runtime" (i.e. they prefer it to fail predictably at start if they made a mistake and forgot to define some required symbol). – Employed Russian Apr 29 '14 at 21:50