std ::在mingw中跨共享库的任何内容 [英] std::any across shared library bounding in mingw

查看:101
本文介绍了std ::在mingw中跨共享库的任何内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在跨共享库边界使用libstdc ++的std :: any mingw时遇到了一个问题.它会产生一个std::bad_any_cast,它显然不应该(我相信).

我使用mingw-w64,gcc-7并使用-std = c ++ 1z编译代码.

简化代码:

main.cpp:

#include <any>
#include <string>

// prototype from lib.cpp
void do_stuff_with_any(const std::any& obj);

int main()
{
    do_stuff_with_any(std::string{"Hello World"});
}

lib.cpp:

将被编译到共享库中,并与main.cpp中的可执行文件链接.

#include <any>
#include <iostream>

void do_stuff_with_any(const std::any& obj)
{
    std::cout << std::any_cast<const std::string&>(obj) << "\n";
}

这将触发std :: bad_any_cast,尽管传递给do_stuff_with_any的any确实包含字符串.我深入研究了gcc的any实现,它似乎使用了静态内联成员函数(根据所存储对象的类型从模板结构中选择的管理器)的地址进行比较,以检查是否有任何对象持有所请求类型的对象. 而且此函数的地址似乎在共享库的边界上发生了变化.

不是std :: any可以跨共享库边界正常工作吗?此代码会在某个地方触发UB吗?还是这是gcc实施中的错误?我很确定它可以在linux上运行,所以这只是mingw中的错误吗?是已知的还是应该在某个地方报告?有任何关于(临时)解决方法的想法吗?

解决方案

虽然这确实是Windows DLL的工作方式问题,但是从GCC 8.2.0开始,问题仍然存在,这很容易通过将any标头中的__any_caster函数更改为此:

template<typename _Tp>
void* __any_caster(const any* __any)
{
  if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
{
#if __cpp_rtti
  if (__any->type().hash_code() == typeid(_Tp).hash_code())
#else
  if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
#endif
    {
      any::_Arg __arg;
      __any->_M_manager(any::_Op_access, __any, &__arg);
      return __arg._M_obj;
    }
}
  return nullptr;
}

或类似的东西,唯一相关的部分是#if中包裹的比较行.

详细说明,管理器函数有2个副本,一个在exe上,一个在dll上,传递的对象包含exe的地址,因为这是创建它的位置,但是一旦到达dll端,则指针会与永远不会匹配的dll地址空间中的地址进行比较,因此,应该比较类型为info hash_codes的信息.

I stumbled about an issue while using libstdc++'s std::any implementation with mingw across a shared library boundary. It produces a std::bad_any_cast where it obviously should not (i believe).

I use mingw-w64, gcc-7 and compile the code with -std=c++1z.

The simplified code:

main.cpp:

#include <any>
#include <string>

// prototype from lib.cpp
void do_stuff_with_any(const std::any& obj);

int main()
{
    do_stuff_with_any(std::string{"Hello World"});
}

lib.cpp:

Will be compiled into a shared library and linked with the executable from main.cpp.

#include <any>
#include <iostream>

void do_stuff_with_any(const std::any& obj)
{
    std::cout << std::any_cast<const std::string&>(obj) << "\n";
}

This triggers a std::bad_any_cast although the any passed to do_stuff_with_any does contain a string. I digged into gcc's any implementation and it seems to use comparison of the address of a static inline member function (a manager chosen from a template struct depending on the type of the stored object) to check if the any holds an object of the requested type. And the address of this function seems to change across the shared library boundary.

Isn't std::any guaranteed to work across shared library boundaries? Does this code trigger UB somewhere? Or is this a bug in the gcc implementation? I am pretty sure it works on linux so is this only a bug in mingw? Is it known or should i report it somewhere if so? Any ideas for (temporary) workarounds?

解决方案

While it is true that this is an issue on how Windows DLLs work, and that as of GCC 8.2.0, the issue still remains, this can be easily worked around by changing the __any_caster function inside the any header to this:

template<typename _Tp>
void* __any_caster(const any* __any)
{
  if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
{
#if __cpp_rtti
  if (__any->type().hash_code() == typeid(_Tp).hash_code())
#else
  if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
#endif
    {
      any::_Arg __arg;
      __any->_M_manager(any::_Op_access, __any, &__arg);
      return __arg._M_obj;
    }
}
  return nullptr;
}

Or something similar, the only relevant part is the comparison line wrapped in the #if.

To elaborate, there is 2 copies of the manager function one on the exe and one on the dll, the passed object contains the address of the exe because that's where it was created, but once it reaches the dll side, the pointer gets compared to the one in the dll address space, which will never match, so, instead type info hash_codes should be compared instead.

这篇关于std ::在mingw中跨共享库的任何内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆