14

未処理のNSExceptionがスローされた場合、スタックトレースには次のようなセクションがあります。

Last Exception Backtrace:
0   CoreFoundation                  0x32bd688f __exceptionPreprocess + 163
1   libobjc.A.dylib                 0x34b7b259 objc_exception_throw + 33
2   CoreFoundation                  0x32bd65c5 -[NSException init] + 1
3   Foundation                      0x37296bd7 -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 263
...

しかし、std :: exceptionがスローされた場合、私はこれだけを取得します:

Thread 0 Crashed:
0   libsystem_kernel.dylib          0x34f2632c __pthread_kill + 8
1   libsystem_c.dylib               0x31e4c208 pthread_kill + 48
2   libsystem_c.dylib               0x31e45298 abort + 88
3   libc++abi.dylib                 0x33bcaf64 abort_message + 40
4   libc++abi.dylib                 0x33bc8346 default_terminate() + 18
5   libobjc.A.dylib                 0x349f4368 _objc_terminate + 164
6   libc++abi.dylib                 0x33bc83be safe_handler_caller(void (*)()) + 70
7   libc++abi.dylib                 0x33bc844a std::terminate() + 14
8   libc++abi.dylib                 0x33bc981e __cxa_rethrow + 82
9   libobjc.A.dylib                 0x349f42a2 objc_exception_rethrow + 6
10  CoreFoundation                  0x329a5506 CFRunLoopRunSpecific + 398
11  CoreFoundation                  0x329a5366 CFRunLoopRunInMode + 98
12  GraphicsServices                0x32af2432 GSEventRunModal + 130
13  UIKit                           0x34f84cce UIApplicationMain + 1074
14  APP_NAME                            0x00086b10 main (main.m:68)
15  APP_NAME                        0x00071b98 start + 32

このクラッシュログから正確なクラッシュ情報を取得するにはどうすればよいですか?

アップデート -

HockeyAppを試してみましたが、iTunesのクラッシュログと同じ制限があります。未処理のC++例外のスタックはわかりません。

4

4 に答える 4

25

あなたが見ているのは、AppKitとUIKitの不幸な癖です。iOSとOSXの両方に、キャッチされCFRunLoopなかったすべての例外をトラップする例外ハンドラーがあります。OS Xでは、ハンドラーはダイアログボックスを使用してユーザーに例外を表示しますが、iOSでは、ハンドラーは単に例外を再スローします。

によって実装されたObjective-C例外は、(または同様の初期化メソッド)のNSException一部として、実際の「スロー」が発生する直前に例外オブジェクト内にバックトレースを保存します。[NSException init]残念ながら、C++例外は同じことをしません。通常、C ++例外にはバックトレースがあります。これは、ランタイムライブラリが、呼び出しがないことを検出してcatchすぐに呼び出しstd::terminate、次に呼び出しabort()を行い、次のように呼び出しスタック全体をそのまま残すためです。

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x00007fff93ef8d46 __kill + 10
1   libsystem_c.dylib               0x00007fff89968df0 abort + 177
2   libc++abi.dylib                 0x00007fff8beb5a17 abort_message + 257
3   libc++abi.dylib                 0x00007fff8beb33c6 default_terminate() + 28
4   libobjc.A.dylib                 0x00007fff8a196887 _objc_terminate() + 111
5   libc++abi.dylib                 0x00007fff8beb33f5 safe_handler_caller(void (*)()) + 8
6   libc++abi.dylib                 0x00007fff8beb3450 std::terminate() + 16
7   libc++abi.dylib                 0x00007fff8beb45b7 __cxa_throw + 111
8   test                            0x0000000102999f3b main + 75
9   libdyld.dylib                   0x00007fff8e4ab7e1 start + 1

ただし、実行ループ例外ハンドラーが例外をトラップすると、catchブロック内で通常どおり実行が再開されます。したがって、元のバックトレースは失われます。その後、再スローはを呼び出しますstd::terminateが、この時点で、呼び出しスタックは実行ループ例外ハンドラーを反映します。

この状況でC++例外からバックトレースを取得するにNSExceptionは、コンストラクターの一部として呼び出しスタックを模倣して読み取る例外オブジェクトをスローし、コードでスローされるすべての例外が同じことを行うようにする必要があります。std::exceptionこれは行われず、使用しているサードパーティのコードもそうなる可能性はまったくありません。

Appleにバグを報告して、CFRunLoop例外ハンドラを削除するか、少なくともそれをシャットオフするためのAPIを提供するように依頼します。現在、これを行うためのAPIはなく、SPIもありません。

于 2012-12-09T01:55:45.710 に答える
3

私はmpipe3の答えを改善することができました。

私のメインメソッドでは、try-catchを使用してC ++例外を取得してから、dispatch_synconを呼び出しますdispatch_get_global_queue。これで、行番号を含む完全なスタックトレースがCrashlytics(クラッシュマネージャー)に表示されます。

int main(int argc, char *argv[]) {

@autoreleasepool {
    @try{
        return UIApplicationMain(argc, argv, nil, @"AppControllerClassName");
    } @catch (NSException *exception) {/* Catch any uncaught exceptions and print out a friendly call stack. Instead of an ugly memory addresses. */
        NSString * message = [NSString stringWithFormat:@"Uncaught exception %@ : %@\n %@", exception.name, exception.reason, [exception callStackSymbols]];
        [LogManager e:@"main.m" Message:message Exception: exception];
        @throw;
    } @catch (...){
        //Attempt to get the correct stacktrace for C++ exceptions.
        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            @throw;
        });
    }
    return 0;
}
}

これは、GCDを使用して例外をスローすることにより、CFRunLoop例外ハンドラーを回避するために機能します。

于 2016-04-20T04:07:13.237 に答える
0

Gwynne Raskindの回答に続いて、GCDを使用してC ++コードのブロックへの呼び出しを同期的にディスパッチすることにより、CFRunLoop例外ハンドラーを回避できます。

namespace
{
    void MyThrowingCode()
    {
        throw std::runtime_error("My Exception");
    }

}

- (void)objcHandlerCalledFromARunLoop
{
   dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        MyThrowingCode();
         });
}

単一の共有キューを使用するのではなく、独自のキューを作成する必要がある場合があります。

クラッシュログは次のようになります。

0   libsystem_kernel.dylib          0x3aa39350 __pthread_kill + 8
1   libsystem_c.dylib               0x3a9affb2 pthread_kill + 54
2   libsystem_c.dylib               0x3a9ec366 abort + 90
3   libc++abi.dylib                 0x39f94dda abort_message + 70
4   libc++abi.dylib                 0x39f92094 default_terminate() + 20
5   libobjc.A.dylib                 0x3a545a70 _objc_terminate() + 168
6   libc++abi.dylib                 0x39f92118 safe_handler_caller(void (*)()) + 76
7   libc++abi.dylib                 0x39f921b0 std::terminate() + 16
8   libc++abi.dylib                 0x39f9359a __cxa_throw + 118
9   Test                            0x000fddfc MyThrowingCode() (MainViewController.mm:177)
10  Test                            0x000fe38c __35-[MainViewController toolsClick:]_block_invoke (MainViewController.mm:184)
11  libdispatch.dylib               0x3a95f5d8 _dispatch_client_callout + 20
12  libdispatch.dylib               0x3a962776 _dispatch_sync_f_invoke + 22
13  Test                            0x000fde90 -[MainViewController toolsClick:] (MainViewController.mm:183)
14  UIKit                           0x34744082 -[UIApplication sendAction:to:from:forEvent:] + 66
15  UIKit                           0x3474410c -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 116
16  UIKit                           0x34744082 -[UIApplication sendAction:to:from:forEvent:] + 66
17  UIKit                           0x34744036 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
18  UIKit                           0x34744010 -[UIControl sendAction:to:forEvent:] + 40
19  UIKit                           0x347438c6 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
20  UIKit                           0x34743db4 -[UIControl touchesEnded:withEvent:] + 484
21  UIKit                           0x3466c5f4 -[UIWindow _sendTouchesForEvent:] + 520
22  UIKit                           0x346598dc -[UIApplication sendEvent:] + 376
23  UIKit                           0x346591ea _UIApplicationHandleEvent + 6194
24  GraphicsServices                0x363715f4 _PurpleEventCallback + 588
25  GraphicsServices                0x36371222 PurpleEventCallback + 30
26  CoreFoundation                  0x3281f3e4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
27  CoreFoundation                  0x3281f386 __CFRunLoopDoSource1 + 134
28  CoreFoundation                  0x3281e20a __CFRunLoopRun + 1378
29  CoreFoundation                  0x32791238 CFRunLoopRunSpecific + 352
30  CoreFoundation                  0x327910c4 CFRunLoopRunInMode + 100
31  GraphicsServices                0x36370336 GSEventRunModal + 70
32  UIKit                           0x346ad2b4 UIApplicationMain + 1116
33  Test                            0x00120462 main (main.mm:55)
34  libdyld.dylib                   0x3a972b1c start + 0
于 2013-05-02T15:43:23.393 に答える
-2

UIApplicationMain()内から例外が発生しているようです...main.mファイルをmain.mmファイルに変換してみてください。

int main(...)
{
    try
    {
        return UIApplicationMain(...);
    }
    catch( exception e )
    {
        cerr < e.what() ;
    }
}

私は実際にそれを試しませんでした、しかし...

于 2012-12-09T02:01:03.757 に答える