Search code examples
c++unique-ptrdlsymextern-c

Returning unique_ptr from a function executed via dlsym


I have a function that is located in a shared object, and is loaded and executed with dlsym from the main program. (both the shared object and the main program are C++)

Is it possible that this function will return std::unique_ptr ?

shared object function -

extern "C" {
    unique_ptr<Obj> some_function() {
        return make_unique<Obj>();
    }
}

main program :

void main_flow() {
    auto handle = dlopen(...);
    FuncPtr func = dlsym(handle, "some_function");
    unique_ptr<Obj> func();
}

Solution

  • Yes, ish, with a lot of caveats. Firstly, using boost or STL within a DSO interface is a little dangerous.

    1. std::unique_ptr differs between compilers
    2. std::unique_ptr differs between C++ versions
    3. std::unique_ptr may differ between debug/release builds.

    This means if you use STL or boost in your DSO interface, ALL exes and dsos must use exactly the same version of the C++ runtime compiled with the same build flags (and same version of boost if that's your kind of thing).

    I'd recommend using warning level 4 on Visual Studio, which will nicely list all of the above problems in your DSO interfaces (As C4251 warnings)

    As for your question, yes the function will return a std::unique_ptr, however you are now allocating memory in the DSO, which you may be freeing in the exe. This can be very bad in the windows world, where you may find that debug builds have different heaps. Attempting to free the DSO allocated object in the EXE heap will throw a runtime error, but usually only in debug builds.

    Your main should look like this:

    void main_flow() {
      auto handle = dlopen(...);
      FuncPtr func = (FuncPtr)dlsym(handle, "some_function");
      unique_ptr<Obj> obj = func();
    }  
    

    Personally though, I'd recommend just returning a naked pointer, and doing a make_unique on it in your exe. That at least removes the C4251 problems, although you may get bitten by the heap issue (unless you make the destructor of the class type virtual)