android / ndk

The Android Native Development Kit
2.01k stars 257 forks source link

[BUG] type_info equality check on same class objects is failing when objects are from two different libraries #926

Closed pendyalasyam closed 5 years ago

pendyalasyam commented 5 years ago

Dear Team,

We have following piece of code in our project which compares the two typeinfos. This is working properly with GNUSTL but failing with libc++.

template<typename T>
bool AreSameTypes(AnyType &any)
{
        //AnyType is capable of storing any data type & TypeInfo() returns 
       // type_info of the data it is holding
    if (typeid(T) == any.TypeInfo())
        return true;
    return false;
}

Here is the scenario:

  1. Above piece of code is present in shared library LIB1.

    From with in this library, there is a call to this function with argument of type std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator> like below.

    Function1(){ ....... std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator> obj; AreSameTypes<std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator>>(obj); ....... }

    Since we are applying typeid() on std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator>, compiler is generating the typeinfo for this class. I can see the typeinfo for class by applying readelf command on the shared library LIB1.

  2. Within LIB1 itself, there is another function like below

    bool Function2(AnyType &anyTypeObj){ //some code return AreSameTypes<std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator>>(obj); }

  3. There is one more shared libary LIB2. LIB2 is creating an object of type std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator> and calling Function2. I did readelf on LIB2 and found typeinfo for std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator> here as well.

With GNUSTL, Function2 is returning true. But with libc++, it is returning false.

To debug the issue, I put log statement inside AreSameTypes and printing the address,name of template argument, received object in order and following is the output

SyamDebug2: 0xc6bc5fc0 NSt6__ndk112basic_stringIwN4wc1614wchar16_traitsENS_9allocatorIwEEEE 0xb9b18380 NSt6__ndk112basic_stringIwN4wc1614wchar16_traitsENS_9allocatorIwEEEE

It seems GNUSTL is comparing the contents whereas libc++ is comparing addresses. Could you please help me how to fix this issue. As of now I can think of two ways to solve this issue.

Solution#1: Make lib2 to use typeinfo generated in lib1 itself. When it is compared, since they are same typeinfos (wrt addresses), it will return true. But I dont know how to make lib2 to depend on lib1 for typeinfo of std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator>. Since ours is product code, touching the code and making logical changes is very difficult.

Solution#2. Make change in typeinfo file in ndk to compare contents instead of addresses. Not sure what are the complications.

Kindly suggest.

DanAlbert commented 5 years ago

https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md#rtti_exceptions-not-working-across-library-boundaries

You can find lots of other discussions of this by searching this bug tracker for "type_info" as well.

libc++ complies with the C++ ABI, gnustl does not. Rationale discussed here: https://lists.llvm.org/pipermail/llvm-dev/2014-June/073465.html

DanAlbert commented 5 years ago

One of those other bugs was even filed by you: https://github.com/android-ndk/ndk/issues/899

pendyalasyam commented 5 years ago

Hi Dan, initially I thought of adding the key function. But std::__ndk1::basic_string<wchar_t, wc16::wchar16_traits, std::__ndk1::allocator> is explicit instantiation of basic_string defined by ndk. So I can not add virtual function to basic_string class.

DanAlbert commented 5 years ago

RTTI doesn't work for non-polymorphic types. You want std::is_same for non-polymorphic types.

pendyalasyam commented 5 years ago

As far as I understand, std::is_same is compile time type verification. But in my case, I am basically doing type verification at runtime.

bool isOfStringType(AnyType obj) //AnyType is local implementation of std::any { //Step1: get object type at runtime. The only way I know as of now is obj.type().name() return string_type == type obtained in above step. }

could you please help me to code "how to check if an object stored in std::any(/AnyType) is of type X or not, where X is non-polymorphic type and objects are passed from different shared library."

DanAlbert commented 5 years ago

The C++ ABI does not support this aiui.

pendyalasyam commented 5 years ago

So, Can I assume C++ ABI can not identify whether two run time objects are of same type if two objects are passed from two different shared libraries (because two objects typeid wont match)?

DanAlbert commented 5 years ago

That's my understanding, yes.

pendyalasyam commented 5 years ago

In that case, we may need to correct our logic. Thanks @DanAlbert for your support.