1

I am seeing a very strange failure that is very similar to the problem described in dynamic_cast on llvm clang compiler failing: dynamic_cast returns nullptr when I am trying to downcast from base type to derived type, for an object of derived type. In my case though typeid actually shows the same dynamic type.

Below is the debug function that I use to verify run-time types. It takes a pointer of SrcType* and tries to dynamically cast it to pointer of DstType*. If conversion fails, i.e. the returned pointer is nullptr, it prints an error message. VERIFY() macro checks if condition is true:

template<typename DstType, typename SrcType>
void CheckDynamicType( SrcType *pSrcPtr )
{
    VERIFY(dynamic_cast<DstType*> (pSrcPtr) != nullptr, 
           "Dynamic type cast failed. Src typeid: \'", typeid(*pSrcPtr).name(), 
           "\' Dst typeid: \'", typeid(DstType).name(), '\'');
}

And here is the output that I am getting:

Dynamic type cast failed. Src typeid: 'N8Diligent15RefCountersImplE' Dst typeid: 'N8Diligent15RefCountersImplE'

I am using clang compiler from Android ndk r16 toolchain. I am compiling with rtti flag. The same code works fine on gcc and msvc. Another bit of information: the code also works fine if I build it with gnustl runtime (I am not sure how gnu stl works with clang, but anyway).

UPDATE

After spending few more hours looking into the issue I found out that dynamic_cast fails when it is used on the object created in another module. From this Using clang++, -fvisibility=hidden, and typeinfo, and type-erasure and this posts it looks like dynamic_cast should work if the class is labeled with __attribute__((visibility("default"))) so that typeid structures from two modules will be merged. This, however does not help either and I am still seeing the issue.

Egor
  • 779
  • 5
  • 20
  • Seems like caused by simple typographical error. – Öö Tiib Nov 16 '17 at 07:37
  • post a [mcve], please – Massimiliano Janes Nov 16 '17 at 08:39
  • @RustyX, why ? as far as I can tell, the semantics of CheckDynamicType is to **pass** if the pointer is either null or the dynamic cast succeeds... – Massimiliano Janes Nov 16 '17 at 08:41
  • Works for me with APP_PLATFORM=android-21, APP_STL=c++_static, APP_ABI=x86, on Mac. Is the pointer *expected* to print the same typeid, or this is an expected indication of compiler bug? – Alex Cohn Nov 16 '17 at 12:52
  • @RustyX sorry about confusing description. `VERIFY()` macro checks if expression is true and prints a debug message otherwise (I updated the question to make this clear). @Öö-Tiib so, it is not a typo. @RustyX `Dynamic type cast failed` is printed if it indeed failed (i.e. `dynamic_cast` returned `nullptr`), but then `typeid` shows the same type, which is my problem – Egor Nov 16 '17 at 16:35
  • @Alex-Cohn the macro only prints debug message if expression evaluates to `false`. So the meaning of the message it prints is that `dynamic_cast` returned `nullptr`, but `typeid` deduces that dynamic types actually match, which does not make sense to me. – Egor Nov 16 '17 at 16:52
  • I believe that you can deduce what the expected **typeid** should be. And if you check the same configuration on your side, this could be a step forward. – Alex Cohn Nov 16 '17 at 17:55
  • @Alex-Cohn The `typeid` printed by the macro is the correct and expected type id. So what happens is that I have `SrcType` and `DstType` for which `typeid(SrcType).name() == typeid(DstType).name()`, but `dynamic_cast(pSrcPtr) == nullptr`. I am using the most recent ndk version, but build for armv7 – Egor Nov 16 '17 at 18:07
  • Please try [this](https://github.com/alexcohn/SO47322895). I used emulator at API=24 – Alex Cohn Nov 16 '17 at 19:32
  • 1
    @Alex-Cohn thank you for looking into this. I found out that it fails because I use `dynamic_cast` on an object created in another module. This turned out to be a known issue and this post http://www.russellmcc.com/posts/2013-08-03-rtti.html#foot1 suggests that labeling class with `__attribute__((visibility("default")))` should help, but I am still seeing the issue. – Egor Nov 17 '17 at 06:20
  • Do you use c++_shared or static? – Alex Cohn Nov 17 '17 at 07:07
  • 1
    @Alex-Cohn I tried both, but neither works. My understanding of the problem is that the compiler generates two identical `typeid` structures in two modules, and then only compares pointers, which are different. It is not related to static or dynamic version of run-time library. Labeling class visibility as default does not help for some reason either. – Egor Nov 17 '17 at 17:40
  • 1
    Please check https://github.com/android-ndk/ndk/issues/533#issuecomment-335977747 – Alex Cohn Nov 19 '17 at 07:06
  • @Alex-Cohn thank you for the link. This looks exactly like the problem I am seeing. – Egor Nov 22 '17 at 02:01
  • 2
    @AlexCohn: Should probably elevate that to an answer so it's more visible. – Dan Albert Nov 28 '17 at 21:44

1 Answers1

-4

If you’re using the stock system compiler there’s a near 0 chance dynamic_cast of the compiler isn’t working. This is tested and used extensively in everything from system software up.

Colin LeMahieu
  • 610
  • 5
  • 7