Search code examples
androidc++exceptioncrashabort

How to debug an Android stack trace with __cxa_rethrow


I am building an Android app which in the latest version has a lot of crash reports like the following one on google play dash. It consists of several libraries cross compiled with android-ndk.

Starting from frame #05 it halfway makes sense to me. What I wonder is how to go for the other half and what to make from the upper frames.

Trace:

  #00  pc 0000000000083134  /apex/com.android.runtime/lib64/bionic/libc.so (abort+160)
  #01  pc 000000000017cf00  /data/app/[...]==/lib/arm64/libqca-qt5_arm64-v8a.so
  #02  pc 000000000017d070  /data/app/[...]==/lib/arm64/libqca-qt5_arm64-v8a.so
  #03  pc 0000000000179f48  /data/app/[...]==/lib/arm64/libqca-qt5_arm64-v8a.so
  #04  pc 0000000000179850  /data/app/[...]==/lib/arm64/libqca-qt5_arm64-v8a.so (__cxa_rethrow+196)
  #05  pc 0000000000c0e10c  /data/app/[...]==/lib/arm64/libqgis_core_arm64-v8a.so (QgsCoordinateTransform::transformInPlace(double&, double&, double&, QgsCoordinateTransform::TransformDirection) const+300)
  #06  pc 00000000000340d8  /data/app/[...]==/lib/arm64/libqfield_qgsquick_arm64-v8a.so (QgsQuickCoordinateTransformer::updatePosition()+136)
  #07  pc 0000000000034350  /data/app/[...]==/lib/arm64/libqfield_qgsquick_arm64-v8a.so (QgsQuickCoordinateTransformer::setDestinationCrs(QgsCoordinateReferenceSystem const&)+176)
  #08  pc 0000000000028488  /data/app/[...]==/lib/arm64/libqfield_qgsquick_arm64-v8a.so
  #09  pc 0000000000028a18  /data/app/[...]==/lib/arm64/libqfield_qgsquick_arm64-v8a.so (QgsQuickCoordinateTransformer::qt_metacall(QMetaObject::Call, int, void**)+316)
  #10  pc 00000000002f36a8  /data/app/[...]==/lib/arm64/libQt5Qml_arm64-v8a.so (QV4::QQmlValueTypeWrapper::write(QObject*, int) const+180)

What I know: QgsCoordinateTransform::transformInPlace can throw a QgsCsException which is caught and handled inside updatePosition().

  try
  {
    mCoordinateTransform.transformInPlace( x, y, z );
  }
  catch ( const QgsCsException &exp )
  {
    QgsDebugMsg( exp.what() );
  }

Given that it's handled I'm not sure how that's related to a crash, nonetheless I think it could be interesting information.

What I can't make sense of is how libqca-qt5 comes into play, this is never used inside transformInPlace. Might it have some magic in place to handle unhandled exceptions (Can something be extracted from __cxa_rethrow)?

The only idea that comes to my mind is that it's not a QgsCsException but another (unhandled) exception that's raised and causes the crash. This would be an easy fix, but since I'm not able to reproduce this and all I have is this stack trace here and the only way to test is to ship a new apk and wait for reports to come in. This is a long roundtrip for feedback, so I'm very interested in either getting things right directly or at least improving the debug possibilities to fix it in two rounds.

So the question: what can be read from a stack trace like this and how to go about debugging this?


Solution

  • After having received feedback from a user about how exactly to reproduce this crash, it was possible to resolve this with the confidence of a positive test.

    As assumed, it was a different exception raised by another library which was called from within transformInPlace().

    Adding the following line fixed the crash and helped at least as a band aid.

      try
      {
        mCoordinateTransform.transformInPlace( x, y, z );
      }
      catch ( const QgsCsException &exp )
      {
        QgsDebugMsg( exp.what() );
      }
      catch ( ... )
      {
        QgsDebugMsg( "Unknown exception caught" );
      }
    

    It is still unclear to me, how qca is involved in this stack trace. And if there is any code to handle unhandled exceptions or if it is just a random library defining some symbols or if there are other mechanisms at play. I assume __cxa_rethrow plays a role, after all it's related to exception handling. I'd still be happy if someone could shed some light. Meanwhile, for future readers, it's good to know that adding a catch all clause is a feasible approach here.