ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 为什么在dlopen’d函数内传递std :: any的std :: any_cast会引发错误

2019-07-27 08:07:34  阅读:251  来源: 互联网

标签:scons dlopen c c17 stdany


我正在玩c 17和插件,我遇到了一个我无法解决的错误.在下面的MWE中,我可以调用一个带有std :: any的本地函数,当我尝试读取内容时,一切都按预期工作.当我通过插件(dlopen)加载这个完全相同的函数时,它正确地看到了any上的类型,但它不能std :: any_cast内容.

在弄清楚导致此错误的原因时,将非常感谢任何帮助.

这是我的环境,MWE和产生的错误.

>> g++ --version

g++ (GCC) 7.1.1 20170526 (Red Hat 7.1.1-2)
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.

>> scons --version

SCons by Steven Knight et al.:
    script: v2.5.1.rel_2.5.1:3735:9dc6cee5c168[MODIFIED], 2016/11/03 14:02:02, by bdbaddog on mongodog
    engine: v2.5.1.rel_2.5.1:3735:9dc6cee5c168[MODIFIED], 2016/11/03 14:02:02, by bdbaddog on mongodog
    engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2016 The SCons Foundation

>> tree

.
├── SConstruct
└── src
    ├── main.cpp
    ├── plugin.cpp
    └── SConscript

1 directory, 4 files

>> cat SConstruct

SConscript('src/SConscript', variant_dir='build', duplicate=0)

>> cat src/SConscript

env = Environment()
env.Append(CXXFLAGS=['-std=c++17'])
plugin = env.SharedLibrary('plugin', 'plugin.cpp')
Install('../lib', plugin)
driver_env = env.Clone()
driver_env.Append(LIBS=['dl', 'stdc++fs'])
driver = driver_env.Program('driver', 'main.cpp')
Install('../bin', driver)

>> cat src/plugin.cpp

#include <any>
#include <iostream>
using namespace std;
extern "C" {
int plugin(any& context) {
    cout << "    Inside Plugin" << endl;
    cout << "    Has Value? " << context.has_value() << endl;
    cout << "    Type Name: " << context.type().name() << endl;
    cout << "    Value: " << any_cast<double>(context) << endl;
}
}

>> cat src/main.cpp

#include <functional>
#include <iostream>
#include <stdexcept>
#include <any>
#include <experimental/filesystem>
#include <dlfcn.h>

using namespace std;
using namespace std::experimental;

function< void(any&) > loadplugin(string filename) {
    function< void(any&) > plugin;
    filesystem::path library_path(filename);
    filesystem::path library_abspath = canonical(library_path);
    void * libraryHandle = dlopen(library_abspath.c_str(), RTLD_NOW);
    if (!libraryHandle) {
        throw runtime_error("ERROR: Could not load the library");
    }
    plugin = (int(*) (any&))dlsym(libraryHandle, "plugin");
    if (!plugin) {
        throw runtime_error("ERROR: Could not load the plugin");
    }
    return plugin;
}

int local(any& context) {
    cout << "    Inside Local" << endl;
    cout << "      Has Value? " << context.has_value() << endl;
    cout << "      Type Name: " << context.type().name() << endl;
    cout << "      Value: " << any_cast<double>(context) << endl;
}

int main(int argc, char* argv[]) {
    cout << "  Resolving Paths..." << endl;
    filesystem::path full_path = filesystem::system_complete( argv[0] ).parent_path();
    filesystem::path plugin_path(full_path/".."/"lib"/"libplugin.so");
    cout << "  Creating Context..." << endl;
    any context(.1);
    cout << "  Loading Plugin..." << endl;
    function<void(any&) > plugin = loadplugin(plugin_path.string());
    cout << "  Calling Local..." << endl;
    local(context);
    cout << "  Calling Plugin..." << endl;
    plugin(context);
}

>> scons

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/main.o -c -std=c++17 src/main.cpp
g++ -o build/driver build/main.o -ldl -lstdc++fs
Install file: "build/driver" as "bin/driver"
g++ -o build/plugin.os -c -std=c++17 -fPIC src/plugin.cpp
g++ -o build/libplugin.so -shared build/plugin.os
Install file: "build/libplugin.so" as "lib/libplugin.so"
scons: done building targets.

>> tree

.
├── bin
│   └── driver
├── build
│   ├── driver
│   ├── libplugin.so
│   ├── main.o
│   └── plugin.os
├── lib
│   └── libplugin.so
├── SConstruct
└── src
    ├── main.cpp
    ├── plugin.cpp
    └── SConscript

4 directories, 10 files

>> bin/driver

  Resolving Paths...
  Creating Context...
  Loading Plugin...
  Calling Local...
    Inside Local
      Has Value? 1
      Type Name: d
      Value: 0.1
  Calling Plugin...
    Inside Plugin
    Has Value? 1
    Type Name: d
terminate called after throwing an instance of 'std::bad_any_cast'
  what():  bad any_cast
    Value: Aborted (core dumped)

解决方法:

libstdc的任何依赖于同一模板实例化的地址在程序中是相同的,这意味着你需要take precautions if you are using dlopen

The compiler has to emit [objects with vague linkage, like template
instantiations] in any translation unit that requires their presence,
and then rely on the linking and loading process to make sure that
only one of them is active in the final executable. With static
linking all of these symbols are resolved at link time, but with
dynamic linking, further resolution occurs at load time. You have to
ensure that objects within a shared library are resolved against
objects in the executable and other shared libraries.

  • For a program which is linked against a shared library, no additional precautions are needed.
  • You cannot create a shared library with the -Bsymbolic option, as that prevents the resolution described above.
  • If you use dlopen to explicitly load code from a shared library, you must do several things. First, export global symbols from the
    executable by linking it with the -E flag (you will have to specify
    this as -Wl,-E if you are invoking the linker in the usual manner
    from the compiler driver, g++). You must also make the external
    symbols in the loaded library available for subsequent libraries by
    providing the RTLD_GLOBAL flag to dlopen. The symbol resolution
    can be immediate or lazy.

标签:scons,dlopen,c,c17,stdany
来源: https://codeday.me/bug/20190727/1551870.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有