c++boostdll

Access Violation exception when calling DLL function loaded with boost import_alias


I am trying to call a function from a DLL. The API for the DLL looks like this:

#pragma once

#include <stdint.h>
#include <stdbool.h>

#if defined _MSC_VER || defined __MINGW32__
    #ifdef __cplusplus
        #define API extern "C" __declspec(dllexport)
    #else
        #define API __declspec(dllexport)
    #endif
#else
    #ifdef __cplusplus
        #define API extern "C" __attribute__((visibility("default")))
    #else
        #define API __attribute__((visibility("default")))
    #endif
#endif


API void* construct(const char* initString);

I am loading that function call using boost, and then trying to call it:

#include <boost/dll/import.hpp>
#include <boost/function.hpp>
#include <boost/filesystem.hpp>
#include <iostream>


typedef void* (ConstructT)(const char*);

int main() {
    boost::function<ConstructT> constructFunc = boost::dll::import_alias<ConstructT>(
        "TestPluginDll.dll",
        "construct",
        boost::dll::load_mode::append_decorations | boost::dll::load_mode::load_with_altered_search_path
    );
    
    std::string initArg = "hello";
    void* pluginInstance = constructFunc(initArg.c_str());
    std::cout << pluginInstance << std::endl;
}

However, it is failing on the call of the constructFunc, throwing an error at the following code in boost/dll/import.hpp:

        // Compilation error at this point means that imported function
        // was called with unmatching parameters.
        //
        // Example:
        // auto f = dll::import_symbol<void(int)>("function", "lib.so");
        // f("Hello");  // error: invalid conversion from 'const char*' to 'int'
        // f(1, 2);     // error: too many arguments to function
        // f();         // error: too few arguments to function
        template <class... Args>
        inline auto operator()(Args&&... args) const
            -> decltype( (*f_)(static_cast<Args&&>(args)...) )
        {
            return (*f_)(static_cast<Args&&>(args)...);
        }

Why is this failing? The type of std::string.c_str() is const char*, so it seems like it is the correct type.

For reference, my DLL code looks like this:

#include <plugin_interface.hpp>
#include <iostream>
#include <nlohmann/json.hpp>


class MyPlugin {
public:
    MyPlugin() {}
};


extern "C" API void* construct(const char* initString) {
    MyPlugin* plugin = new MyPlugin();
    return static_cast<void*>(plugin);
}

The exception:

Exception has occurred: W32/0xC0000005
Unhandled exception at 0x00007FF77B713633 in tmp.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

Exception thrown


Solution

  • After even further investigation i've realized that boost is actually working as intended. The problem is caused by wrong usage of boost::dll::import_alias. It is supposed to be used only with special symbols exported from library via BOOST_DLL_ALIAS macro. alias in this context is a variable in global namespace with plain name containing a pointer to actually exported deeply nested function. see Factory method in plugin

    #include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS   
    #include "../tutorial_common/my_plugin_api.hpp"
    
    namespace my_namespace {
    
    class my_plugin_aggregator : public my_plugin_api {
        float aggr_;
        my_plugin_aggregator() : aggr_(0) {}
    
    public:
        std::string name() const {
            return "aggregator";
        }
    
        float calculate(float x, float y) {
            aggr_ += x + y;
            return aggr_;
        }
    
        // Factory method
        static boost::shared_ptr<my_plugin_aggregator> create() {
            return boost::shared_ptr<my_plugin_aggregator>(
                new my_plugin_aggregator()
            );
        }
    };
    
    
    BOOST_DLL_ALIAS(
        my_namespace::my_plugin_aggregator::create, // <-- this function is exported with...
        create_plugin                               // <-- ...this alias name
    )
    
    } // namespace my_namespace
    

    Since construct is just a regular function in global namespace it can be imported with boost::dll::import_symbol

    boost::function<ConstructT> constructFunc = boost::dll::import_symbol<ConstructT>(
            "TestPluginDll.dll",
            "construct",
            boost::dll::load_mode::append_decorations | boost::dll::load_mode::load_with_altered_search_path
        );