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

The name of the pictureThe name of the pictureThe name of the pictureClash 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





Please provide a Minimal, Complete, and Verifiable example of your code demonstrating this exception
– Barry
Aug 5 at 21:10





@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.

Popular posts from this blog

make 2 or more post in bootsrap

Store custom data using WC_Cart add_to_cart() method in Woocommerce 3

Firebase Auth - with Email and Password - Check user already registered