c++shared-librariesdynamic-loadingdlsym

Alternatives to dlsym() and dlopen() in C++


I have an application a part of which uses shared libraries. These libraries are linked at compile time.
At Runtime the loader expects the shared object to be in the LD_LIBRARY_PATH , if not found the entire application crashes with error "unable to load shared libraries".Note that there is no guarantee that client would be having the library, in that case I want the application to leave a suitable error message also the independent part should work correctly.

For this purpose I am using dlsym() and dlopen() to use the API in the shared library. The problem with this is if I have a lot of functions in the API, i have to access them Individually using dlsym() and ptrs which in my case are leading to memory corruption and code crashes.

Are there any alternatives for this?


Solution

  • The common solution to your problem is to declare a table of function pointers, to do a single dlsym() to find it, and then call all the other functions through a pointer to that table. Example (untested):

    // libfoo.h
    struct APIs {
       void  (*api1)(void);
       void *(*api2)(int);
       long  (*api3)(int, void *);
    };
    
    // libfoo.cc
    void fn1(void) { ... }
    void *fn2(int) { ... }
    long fn3(int, void *) { ... }
    
    APIs api_table = { fn1, fn2, fn3 };
    
    
    // client.cc
    #include "libfoo.h"
    ...
      void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
      if (!foo_handle) {
         return false;            // library not present
      }
      APIs *table = dlsym(foo_handle, "api_table");
      table->api1();              // calls fn1
      void *p = table->api2(42);  // calls fn2
      long x = table->api3(1, p); // calls fn3
    

    P.S. Accessing your API functions individually using dlsym and pointers does not in itself lead to memory corruption and crashes. Most likely you just have bugs.

    EDIT:
    You can use this exact same technique with a 3rd-party library. Create a libdrmaa_wrapper.so and put the api_table into it. Link the wrapper directly against libdrmaa.so.

    In the main executable, dlopen("libdrmaa_wrapper.so", RTLD_NOW). This dlopen will succeed if (and only if) libdrmaa.so is present at runtime and provides all API functions you used in the api_table. If it does succeed, a single dlsym call will give you access to the entire API.