Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual functions in dynamically linked C++ libs impossible?

As an example, this code segfaults (see comment in main.cpp).

hello.h

struct A { virtual ~A() {} };

hello.cpp

#include "hello.h"

extern "C" {
    void hello(A*& a) {
        a = new A;
    }
}

main.cpp:

#include <cassert>
#include <dlfcn.h>

#include "hello.h"

int main() {

    void* handle = dlopen("./hello.so", RTLD_LAZY);
    assert(handle);

    typedef void (*hello_t)(A*& a);
    hello_t hello = (hello_t) dlsym(handle, "hello");
    assert(hello);

    A* a = nullptr;
    hello(a);
    dlclose(handle);

    delete a; // -> segfault
}

compile

g++ -Wall -std=c++11 -g main.cpp -ldl -o main
g++ -Wall -std=c++11 -g -shared -fpic hello.cpp -o hello.so

The reason: A contains a virtual table. When a is being allocated, the virtual table contains pointers to the function segment of hello.so. After a call to dlclose(), this function segment may get invalid, causing the pointers to get invalid, and thus, the delete a calls functions which are out of memory.

So far so clear. My questions are, all assuming that you dlclose() your library and then continue using the objects:

  1. Is it impossible to allocate objects of classes with virtual destructors in an .so file? Is there no better trick than implementing your own vtable on the heap?
  2. If it is impossible, isn't it dangerous to allocate anything you don't know about in a shared library? Even if you know that std::string is guaranteed to be implemented without a virtual destructor, who knows if it holds an internal object with one?
like image 573
Johannes Avatar asked Oct 15 '25 14:10

Johannes


1 Answers

There is no problem with dynamically linked libraries. They are not dangerous.

However, you are demonstrating the problem of unloading dynamically loaded libraries. You can't unload a library and then continue to use references to data in that library: data pointers, function pointers, virtual functions, et cetera. It is just like using a pointer after you delete it: the only answer is to avoid calling delete until you are done with the object.

So, using dynamically loaded libraries with dlopen() and dlclose() are as dangerous as new and delete... there is nothing to prevent you from doing the wrong thing, you have to know how to use these features correctly.

In typical usage (without dynamic loading), a dynamically linked library will remain resident for the entire duration of the program's execution. So if std::string is in a dynamic library, its functions will always be available. Just like a static library.

like image 108
Dietrich Epp Avatar answered Oct 17 '25 04:10

Dietrich Epp



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!