clang compiled program throws std::bad_any_cast during std::any_cast

Clash Royale CLAN TAG#URR8PPP
clang compiled program throws std::bad_any_cast during std::any_cast
I'm working on an application where I use std::any.
std::any
Recently I've discovered that when I compile it with clang I'm getting bad_any_cast exception on one of the std::any_casts.
bad_any_cast
std::any_cast
I'm sure I'm casting to right type. I've added some dumps of typeid(T).name() to cout to be sure there is no difference between type inserted into std::any and type i'm trying to cast to.
typeid(T).name()
cout
std::any
I was trying to write simple program to demonstrate it but I cannot reproduce it.
What's worth mentioning:
I'm passing a pack of std::any (each contains different type inside) and only one has problems (its a std::map<ENUM, int>).
std::any
std::map<ENUM, int>
Problem disappears when I switch to boost::any (or if I build my app with gcc).
boost::any
I've dived into std::any_cast implementation and it fails on:
std::any_cast
template<typename _Tp>
void* __any_caster(const any* __any)
if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
return nullptr;
Second if statement with (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage) doesn't pass.
(__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
It seems to me like there are a few instances of any::_Manager<decay_t<_Tp>>::_S_manage for the same _Tp (possibly caused by my application consisting of a few modules) but I cannot reproduce it on a simpler example.
any::_Manager<decay_t<_Tp>>::_S_manage
_Tp
Do you guys have any suggestions or hints how can I deal with it?
EDIT
Inspired by comments and answers, I've created example where I mess up with default visibility (which is also something I do in my app) and that seems to be the root of the problem.
Files:
lib.cpp
#include <any>
#include <map>
enum class D
a,
b,
c,
d,
e,
;
int read(const std::any& a)
auto map = std::any_cast<std::map<D, int>>(a);
return map.begin()->second;
std::any create()
std::map<D, int> b = D::c, 5 ;
std::any a(b);
return a;
lib2.cpp
#include <any>
#include <map>
std::any create();
int read(const std::any& a);
__attribute__ ((visibility("default"))) std::any build_bar2()
return create();
__attribute__ ((visibility("default"))) int read_foo2(const std::any& a)
return read(a);
lib3.cpp
#include <any>
#include <map>
int read(const std::any &);
std::any create();
__attribute__ ((visibility("default"))) int read_foo3(const std::any& a)
return read(a);
__attribute__ ((visibility("default"))) std::any build_bar3()
return create();
main.cpp
#include <any>
int read_foo2(const std::any& a);
std::any build_bar2();
int read_foo3(const std::any& a);
std::any build_bar3();
int main()
const std::any& a = build_bar3();
int av = read_foo2(a);
const std::any& b = build_bar2();
int bv = read_foo3(a);
return av == bv? 1: 0;
Makefile
CPP=clang++
all: main
lib.o: lib.cpp
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -c lib.cpp -o lib.o
lib2.so: lib2.cpp lib.o
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib2.cpp lib.o -o lib2.so
lib3.so: lib3.cpp lib.o
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib3.cpp lib.o -o lib3.so
main: main.cpp lib3.so lib2.so
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 main.cpp ./lib2.so ./lib3.so -o main
clean:
rm -f ./lib.o ./lib2.so ./lib3.so ./main
So I have 2 shared libraries which are linking common static lib responsible for std::any creation and casting. When std::any is created in one instation of static lib and casted in another I get an exception.
std::any
std::any
@Barry the whole deal is that I cannot reproduce it. I was hoping for someone having the same issue (caused by compiler bug?) or suggestion what can go wrong with
std::any with given implementation so I can generate smaller example and fill a bug (if it really is a bug, not a platform/ABI/linker/whatever limitation). I was trying to build a shared library constructing std::any and then passing it to another library where it is casted (as that's the root of the problem IMHO) but it all works fine.– Michał Walenciak
Aug 6 at 8:02
std::any
std::any
@MichałWalenciak you can reproduce it in your full code. Can't you cut down your code by removing code bit by bit. Sure this takes quite a bit of time, but otherwise this question is just based around a lot of speculation.
– PeterT
Aug 6 at 8:56
1 Answer
1
If you're on a Unix like Linux or OS X, the C++ type ID is handled by a pointer to type information, not a name string match.
That means that if you have shared libraries or static libraries that have the "same" type, but they have their own individual copies of it, the type info will not match up.
This may or may not be your situation.
I believe you'll have to define your types used in your any in a common shared library, declared with default visibility. That should make all of your other shared libraries use that copy instead of a hidden copy from their static library.
any
If two libraries define the same type (by name) and you're trying to cast to one of these shared types, won't the result be a linker error of sorts?
– rubenvb
Aug 6 at 8:37
@rubenvb it could conceivably be two non-exported types with the same name (potentially from the same header), wrapped in an any type when passing library boundaries. But speculating on this is really not all that useful, this question would really benefit from a reproduction example.
– PeterT
Aug 6 at 8:54
I've added a working example
– Michał Walenciak
Aug 7 at 9:30
@MichałWalenciak I added a possible solution.
– Zan Lynx
Aug 7 at 19:51
@ZanLynx thx for your answer Zan, but my case is a little bit more complicated I guess - instead of a common static library like in my simple example, I have a template used in a few shared libraries. What's interesting, only the enum seems to be problematic type. Other (complex) types are working (when placed into
std::any). Anyway I'll need to figure out some nice mechanism to protect me against such problems in the future.– Michał Walenciak
Aug 7 at 21:07
std::any
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Please provide a Minimal, Complete, and Verifiable example of your code demonstrating this exception
– Barry
Aug 5 at 21:10