我正在尝试从 DLL 调用函数。 DLL 的 API 如下所示:
#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);
我正在使用 boost 加载该函数调用,然后尝试调用它:
#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;
}
但是,它在调用
constructFunc
时失败,在 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)...);
}
为什么会失败?
std::string.c_str()
的类型是 const char*
,所以看起来它是正确的类型。
作为参考,我的 DLL 代码如下所示:
#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);
}
例外:
Exception has occurred: W32/0xC0000005
Unhandled exception at 0x00007FF77B713633 in tmp.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
我已成功重现此问题并决定进行调查。事实证明,该问题是 boost.dll 中的一个错误。
import_alias
为 dll.get
重载提供了错误的类型,导致其执行无效的转换并返回垃圾值而不是对导入函数的引用。
boost/dll/import.hpp
如果
T
这里是ConstructT
template <class T>
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(const boost::dll::fs::path& lib, const char* name,
load_mode::type mode = load_mode::default_mode)
{
typedef typename boost::dll::detail::import_type<T>::base_type type;
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(lib, mode);
return type(p, p->get<T *>(name));
}
boost/dll/shared_library.hpp
然后
T
这里是 ConstructT *
导致 aggressive_ptr_cast
转换为指针到指针,造成混乱。
//! \overload T& get(const std::string& symbol_name) const
template <typename T>
inline typename boost::disable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T&>::type get(const char* symbol_name) const {
return *boost::dll::detail::aggressive_ptr_cast<T*>(
get_void(symbol_name)
);
}
快速修复相当简单
return type(p, p->get<T>(name));
。更突出的解决方案是正确检查提供的类型对于 get
过载是否有意义。看起来应该带有函数指针的指针丢失了。
必须更新Boost库。