Skip to content
Advertisement

dlopen Segmentation fault error when get a instance from shared library’s exported function

I have been stuck in a problem for several days when using dlopen/dlsym to deal with the shared object. I desperately need your help!

There are three headers/source files: Animal.h, Animal.cpp and test.cpp, and two products: libanimal.so and a.out.

Here is the source code:

Animal.h:

// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>

class Animal {
public:
    Animal();
    std::string shout();
};

extern "C" Animal* createAnimal();

#endif //STDLIB_ANIMAL_H

Animal.cpp

// Animal.cpp
#include "Animal.h"

Animal::Animal() = default;

std::string Animal::shout() {
    return "WOW";
}

Animal* createAnimal() {
    return new Animal();
}

and the last one test.cpp which contained the main entry of the application:

// test.cpp
#include <cstdio>
#include <cstdlib>
#include <string>
#include <dlfcn.h>
#include <iostream>
#include "Animal.h"

int main(int argc, char** argv)
{
    void *handle;
    // Open shared library
    handle = dlopen("./libanimal.so", RTLD_LAZY);
    if (!handle) {
        /* fail to load the library */
        fprintf(stderr, "Handle Error: %sn", dlerror());
        return EXIT_FAILURE;
    }

    auto spawnAnimal = reinterpret_cast<Animal* (*)()>(dlsym(handle, "createAnimal"));

    if (!spawnAnimal) {
        /* no such symbol */
        fprintf(stderr, "No Such Symbol Error: %sn", dlerror());
        dlclose(handle);
        return EXIT_FAILURE;
    }
    auto animal = spawnAnimal();
    std::cout << "call animal shout, the address of animal : " << animal <<std::endl;
    std::cout << animal->shout() << std::endl;
    std::cout << "after calling" << std::endl;
    dlclose(handle);

    return EXIT_SUCCESS;
}

First, I built libanimal.so shared library by the following command:

$ g++ -shared -fPIC -Wall -o libanimal.so Animal.cpp -std=c++0x

Then I built the executable, a.out:

$ g++ -Wall test.cpp -ldl -std=c++0x -Wl,--unresolved-symbols=ignore-in-object-files
# --unresolved-symbols=ignore-all: tell linker to stop complaining about missing symbols

Both the above commands ran well without any error, but when I execute a.out, errors came out:

$ ./a.out
call animal shout, the address of animal : 0x7fffe97a4520
Segmentation fault (core dumped)

I have searched lots of blogs/documentations, but all of them just post a really simple example:
The function they export always return like a std::string or char or int which is built-in type, not something like a object of a user-defined class, just like the showcase above (the createAnimal function).

So what’s wrong with this? Could you please help me figuring out ?
Thank you !

BTW, my environment is:

$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Advertisement

Answer

Ok, my suspicion from the comment has confirmed itself. The problem is with the early binding on animal->shout() which resolves at compile time to a call to _ZN6Animal5shoutB5cxx11Ev and this symbol is nowhere to be found.

If I change it to virtual (late binding, resolved at runtime through a vtable):

// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>

class Animal {
public:
    Animal();
    virtual std::string shout();
    virtual ~Animal() {} // always put a virtual destructor if you have any virtual methods
};

extern "C" Animal* createAnimal();

#endif //STDLIB_ANIMAL_H

Now it runs.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement