Kscrash: 組み込みフレームワークでのC ++例外の誤ったスタックトレース

作成日 2017年02月20日  ·  12コメント  ·  ソース: kstenerud/KSCrash

組み込みフレームワーク(Crash-TesterアプリのCrashLibなど)でC ++例外がスローされた場合、KSCrashMonitor_CPPException.cの__cxa_throw関数が呼び出されていないようです。

私はこれに対する解決策を思い付くことができませんでした。 私には、組み込みライブラリは常にlibc ++の__cxa_throwを使用し、KSCrashの実装は使用しないように見えます。

さらに、組み込みフレームワークで未処理のC ++例外がスローされると、KSCrashReport.c:writeBacktrace()でstackCursor-> AdvanceCursorがNULLに等しくなるため、レポート中にKSCrashがクラッシュします。

編集:レポート中にKSCrashがクラッシュするという情報を追加しました。

最も参考になるコメント

さらに調査したところ、以前のコメントは正しくなかったようです。

この問題は、_ "KSCrashに静的にリンクされていないイメージからスローされたC ++例外のスタックトレースがありません" _のような名前に変更する必要があると思います。

KSCrashが静的ライブラリとしてメインアプリケーションにリンクされている場合:

  • MyApplicationmain.olibKSCrash.a

    • libDynamicLibrary.dyliblib.o

    • /usr/lib/libc++abi.dylib

MyApplicationからスローされた例外は、 libKSCrash.a::__cxa_throwに入ります。 さらに、 libKSCrash.a __cxa_throwweak $として宣言するため、 main.oに独自の__cxa_throwがある場合、 MyApplicationのリンクは失敗しません。 __cxa_throwオーバーライド。 ここまでは順調ですね。 ただし、このバグレポートで確認されているように、 libDynamicLibrary.dylibからスローされた例外は、 libKSCrash.a::__cxa_throwをトリガーせず、最終的に/usr/lib/libc++abi.dylib::__cxa_throwになります。

KSCrashがダイナミックライブラリとしてメインアプリケーションにリンクされている場合:

  • MyApplicationmain.o

    • libKSCrash.dylib

    • /usr/lib/libc++abi.dylib

    • libDynamicLibrary.dyliblib.o

    • /usr/lib/libc++abi.dylib

MyApplicationからスローされた例外は、 libKSCrash.dylib::__cxa_throwに入りますが、次の場合に限ります。

  1. __cxa_throwlibKSCrash.dylibからエクスポートされます
  2. __cxa_throwweakとしてマークされていません

__cxa_throwweak0000000000002e90 (__TEXT,__text) weak external ___cxa_throw )としてマークされている場合、 libKSCrash.dylibをリンクすると、リンカーは/usr/lib/libc++abi.dylibを参照しているように見えます。 - __cxa_throwが弱く、 libKSCrash.dylib::__cxa_throwは無視する必要があると結論付けます。 MyApplicationからのスロー時の実行時シンボルルックアップ中に、 libKSCrash.dylib::__cxa_throwは無視されます。

これにより、静的ライブラリとしてKSCrashをビルドする場合にのみ、 weak属性を条件付きで追加する必要があると思います。

最初のユースケースと同様に、 libDynamicLibrary.dylibからスローされた例外は、 libKSCrash.dylib::__cxa_throwをトリガーせず、最終的に/usr/lib/libc++abi.dylib::__cxa_throwになります。

この問題は、 __cxa_throwへの未定義の参照を含むロードされたイメージの低レベルのランタイムパッチで修正される可能性があります。 この記事で参照されているテストアプリケーションを使用して、この手法が実際に__cxa_throwでも機能することを確認しました。

cooked_throw

全てのコメント12件

これで運がいいですか? KSCrashをアプリに統合しようとしていますが、フレームワークが埋め込まれているためにスタックします。
これを回避する方法があれば教えてください。

運が悪い、そして少なくとも私たちのユースケースではそれが可能だとは思わない。 これは状況についての私の理解です:

KSCrashがスタックトレースを記録する方法は、__ cxa_throwの独自の実装を作成することです。これにより、libc ++によってスタックが巻き戻される前にスタックにアクセスできます。 これは、リンカがlibc ++での実装の代わりにKSCrashから__cxa_throwを見つけて使用するため、KSCrashがC ++コードと静的にリンクされている限り機能します。 ただし、libc ++にリンクする組み込みフレームワークの場合、フレームワークはKSCrashのコードを認識しないため、libc ++からの__cxa_throw実装が使用されます。 組み込みフレームワークを制御できる場合は回避策があるかもしれませんが、これは私たちのユースケースでは機能しません。

解決策がわかれば教えてください。

組み込みフレームワークを制御できます。 しかし、それを修正する方法がわかりません。
PLCrashReporterも試しましたが、同じ問題があります。

これは、少なくともアプリケーションコードでスローされたC ++例外をキャッチするために、KSCrashを静的ライブラリとして構築し、アプリケーションにリンクすることが理想的であることを意味しますか?

しかし、バグレポートを正しく理解していれば、KSCrashによってキャッチされないダイナミックライブラリにスローされた例外は残りますか? @pdrtrifork ? 埋め込まれた動的ライブラリを制御する場合、共有KSCrashハンドラーに従うだけの__cxa_throwスタブを使用して、静的ライブラリを各ライブラリにリンクできますか?

ああ、それでこれを調査することで私はここに行き着きましたhttp://stackoverflow.com/questions/36846628/conditionally-overriding-cxa-throw 、それは私たち自身の@kstenerudによって開かれました😄

とにかく、PR#219は、少なくともクラッシュレポート中のクラッシュを防ぐ必要があります。

@kstenerudこの問題は、_ "KSCrashに静的にリンクされていないイメージからスローされたC ++例外のスタックトレースがありません" _のような名前に変更する必要があると思います。 私の知る限り、 __cxa_throwオーバーライドは、KSCrashと同じイメージでのみ機能するため、次のようになります。

  • KSCrashが静的ライブラリとしてビルドされ、メインアプリにリンクされている場合、例外がメインアプリでスローされた場合は、C ++例外バックトレースを取得しますが、動的にロードされたライブラリからスローされた場合は取得しません。
  • KSCrashが静的ライブラリとして構築され、動的(ラッパー)ライブラリにリンクされている場合、例外がその動的ライブラリからスローされた場合はC ++例外バックトレースを取得しますが、メインアプリやその他の動的にロードされたライブラリからスローされた場合は取得しません。
  • KSCrashが共有ライブラリ(フレームワーク)としてビルドされている場合、例外がKSCrashからスローされた場合は、C ++例外バックトレースを取得しますが、メインアプリやその他の動的にロードされたライブラリからスローされた場合は取得しません。

後者は、KSCrashをフレームワークとして組み込んだsentry-swifthttps: //docs.sentry.io/clients/cocoa/などのクライアントに影響します。

さらに調査したところ、以前のコメントは正しくなかったようです。

この問題は、_ "KSCrashに静的にリンクされていないイメージからスローされたC ++例外のスタックトレースがありません" _のような名前に変更する必要があると思います。

KSCrashが静的ライブラリとしてメインアプリケーションにリンクされている場合:

  • MyApplicationmain.olibKSCrash.a

    • libDynamicLibrary.dyliblib.o

    • /usr/lib/libc++abi.dylib

MyApplicationからスローされた例外は、 libKSCrash.a::__cxa_throwに入ります。 さらに、 libKSCrash.a __cxa_throwweak $として宣言するため、 main.oに独自の__cxa_throwがある場合、 MyApplicationのリンクは失敗しません。 __cxa_throwオーバーライド。 ここまでは順調ですね。 ただし、このバグレポートで確認されているように、 libDynamicLibrary.dylibからスローされた例外は、 libKSCrash.a::__cxa_throwをトリガーせず、最終的に/usr/lib/libc++abi.dylib::__cxa_throwになります。

KSCrashがダイナミックライブラリとしてメインアプリケーションにリンクされている場合:

  • MyApplicationmain.o

    • libKSCrash.dylib

    • /usr/lib/libc++abi.dylib

    • libDynamicLibrary.dyliblib.o

    • /usr/lib/libc++abi.dylib

MyApplicationからスローされた例外は、 libKSCrash.dylib::__cxa_throwに入りますが、次の場合に限ります。

  1. __cxa_throwlibKSCrash.dylibからエクスポートされます
  2. __cxa_throwweakとしてマークされていません

__cxa_throwweak0000000000002e90 (__TEXT,__text) weak external ___cxa_throw )としてマークされている場合、 libKSCrash.dylibをリンクすると、リンカーは/usr/lib/libc++abi.dylibを参照しているように見えます。 - __cxa_throwが弱く、 libKSCrash.dylib::__cxa_throwは無視する必要があると結論付けます。 MyApplicationからのスロー時の実行時シンボルルックアップ中に、 libKSCrash.dylib::__cxa_throwは無視されます。

これにより、静的ライブラリとしてKSCrashをビルドする場合にのみ、 weak属性を条件付きで追加する必要があると思います。

最初のユースケースと同様に、 libDynamicLibrary.dylibからスローされた例外は、 libKSCrash.dylib::__cxa_throwをトリガーせず、最終的に/usr/lib/libc++abi.dylib::__cxa_throwになります。

この問題は、 __cxa_throwへの未定義の参照を含むロードされたイメージの低レベルのランタイムパッチで修正される可能性があります。 この記事で参照されているテストアプリケーションを使用して、この手法が実際に__cxa_throwでも機能することを確認しました。

cooked_throw

アプリのフレームワークでクラッシュをチェックしようとしています。 クラッシュログを取得しようとすると、スタックトレースに実際のクラッシュが表示されておらず、代わりにKSCrashがクラッシュしていることがわかります。

これは同じ問題ですか?

スレッド0がクラッシュしました:
0 libsystem_kernel.dylib 0x0000000181cc5348 0x181ca4000 + 136008(__ pthread_kill + 8)
1 libsystem_pthread.dylib 0x0000000181ddd7a4 0x181dd6000 + 30628(+ 360)
2 libsystem_c.dylib 0x0000000181c34fd8 0x181bd2000 + 405464(中止+ 140)
3 libc ++ abi.dylib 0x0000000181698068 0x181696000 + 8296(+ 132)
4 libc ++ abi.dylib 0x0000000181698210 0x181696000 + 8720(+ 304)
5 libobjc.A.dylib 0x00000001816c0810 0x1816b8000 + 34832(+ 124)
6 KSCrash 0x00000001054a0590 0x10549c000 + 17808(kscm_cppexception_getAPI + 280)
7 libc ++ abi.dylib 0x00000001816b054c 0x181696000 + 107852(+ 16)
8 libc ++ abi.dylib 0x00000001816b0158 0x181696000 + 106840(__ cxa_rethrow + 144)
9 libobjc.A.dylib 0x00000001816c06e8 0x1816b8000 + 34536(objc_exception_rethrow + 44)
10 CoreFoundation 0x0000000182072344 0x18206a000 + 33604(CFRunLoopRunSpecific + 544)
11 GraphicsServices 0x0000000183f03f84 0x183ef9000 + 44932(GSEventRunModal + 100)
12 UIKit 0x000000018b61e880 0x18b5ab000 + 473216(UIApplicationMain + 208)

@torarnvこんにちは、成功したmach-o-hookデモを私たちと共有できますか? mach_hook __cxa_throwを実行しようとすると、EXC_BAD_ACCESSに遭遇しました。

void ter_handler(){
    printf("custom handler\n");
}

void test(){
    throw std::runtime_error("test function");
}

static void (*orig_throw)(void * thrown_exception, std::type_info *tinfo, void (*dest)(void *));

void hooked_throw(void * thrown_exception, std::type_info *tinfo, void (*dest)(void *)){
    printf("hooked_throw...\n");
    return orig_throw(thrown_exception, tinfo, dest);
}

int main(int argc, char * argv[])
{
    <strong i="5">@autoreleasepool</strong> {

        struct rebinding binds[1];
        struct rebinding bind1 = {"__cxa_throw", (void *)hooked_throw, (void **)&orig_throw};
        binds[0] = bind1;
        rebind_symbols(binds, 1);

        std::set_terminate(ter_handler);
        try {
            throw std::runtime_error("test error");
        }
        catch (...){
            printf  ("catch exception\n");
        }

        test();
    }
}

これを試してください...頑張ってください

KSCrashで1つのクラッシュに遭遇しました。
kscrash

それを解決する方法は?

@huakuchaによって上記の動的フックを実装するPRを作成しました:#375

このページは役に立ちましたか?
0 / 5 - 0 評価