Search code examples
c++classinheritancepolymorphismdlsym

Loading a C++ class with polymorphism using dlsym()


I have a C++ program which I need to open a shared object (.so) and load a C++ class from it. I have seen this done on the internet and I have loaded many things using dlsym() in both C and C++, so I know how everything works. However, there is a slight difference I need to make. The class I am loading with dlsym() must be a child class of another class which is defined in a header used by both the shared object and the main program. The idea is to load a bunch of different custom versions of this class at runtime. Linking with the object at compile-time is not an option. Here is what I have done (heavily abbreviated, but all the important parts are there):

BaseClass.h:

class BaseClass {
    public:
        virtual ~BaseClass();
        virtual int function(int, int);
};

ChildClass.h:

extern "C" BaseClass* makechild();

ChildClass.cpp:

class ChildClass : public BaseClass {
    public:
        int function(int a, int b) override { return a + b; }
};

BaseClass* makechild() {
    return new ChildClass();
}

main.cpp:

std::function<BaseClass*(void)> make;

// note that in the actual program I throw a std::runtime_error with
// dlerror() as its message when this goes wrong, and I don't handle it
make = reinterpret_cast<BaseClass*(*)(void)>(dlsym(handle, "makechild"));

BaseClass* myclass = make();

I then compile the ChildClass.cpp as ChildClass.so (using -shared -fpic) and I compile main.cpp with -ldl and some other warning-related flags and such. Using g++ and clang++ I get two different errors at runtime:

  • After compiling with clang++: undefined symbol: _ZN9BaseClassD2Ev
  • After compiling with g++: undefined symbol: _ZTI9BaseClass

After checking the .so file with objdump and readelf, I confirm that this symbol is indeed undefined:

...
0000000000000000         *UND*  0000000000000000              _ZN9BaseClassD2Ev
...
0000000000000000         *UND*  0000000000000000              _ZTI9BaseClass
...

I am not sure what these symbols mean exactly. After a little bit of reading of the ABI docs, it seems the first might be a dtor or something, and the second is probably the ctor or the class itself, something like that. In any case, I am not explicitly trying to load these, but I am not sure why they are undefined. Is it possible to do this polymorphism/inheritance setup with dlsym() and C++?

Edit: Thanks to a comment, I have used the C++filt program to find out that the destructor was missing (I just added virtual ~BaseClass() = default; to fix that). Now the one thing missing is the _ZTI one, which is the typeinfo for the class.


Solution

  • As it turns out, the destructor and the typeinfo were the symbols which were undefined. Given how many times I've done things like this, I should have seen that, but nobody's perfect. Anyway, all I did to fix this was add = default for BaseClass::~BaseClass and = 0 for BaseClass::function. Thanks a lot to user G.M. in the comments on my original post for bringing this up!