iOS:如何获取未处理的 std::exception 的堆栈跟踪? [英] iOS: How to get stack trace of an unhandled std::exception?

查看:34
本文介绍了iOS:如何获取未处理的 std::exception 的堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果抛出未处理的 NSException,堆栈跟踪将有如下部分:

If an unhandled NSException is thrown, the stack trace has a section like this:

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 被抛出,我只得到这个:

But if std::exception is thrown, i get only this:

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

如何从该崩溃日志中获取准确的崩溃信息?

How do I get the exact crash info from this crash log?

更新--

我已经尝试过 HockeyApp,但它与 iTunes 崩溃日志具有相同的限制 - 它不会告诉我未处理的 C++ 异常的堆栈.

I've given HockeyApp a shot, but it has the same limitation as iTunes crash logs - it doesn't tell me the stack for an unhandled C++ exception.

推荐答案

你看到的是 AppKit 和 UIKit 的一个不幸的怪癖.iOS 和 OS X 在 CFRunLoop 中都有一个异常处理程序,用于捕获所有未捕获的异常.在 OS X 上,处理程序通过对话框向用户显示异常,但在 iOS 上,处理程序只是重新抛出异常.

What you're seeing is an unfortunate quirk of AppKit and UIKit. Both iOS and OS X have an exception handler in CFRunLoop that traps all uncaught exceptions. On OS X, the handler displays the exception to the user with a dialog box, but on iOS, the handler simply rethrows the exception.

Objective-C 异常,由 NSException 实现,在实际抛出"发生之前将它们的回溯保存在异常对象中,作为 [NSException init] 的一部分(或类似的初始化方法).不幸的是,C++ 异常不会做同样的事情.通常,C++ 异常具有回溯,因为运行时库检测到没有 catch 并立即调用 std::terminate,而后者又调用 abort(),保持整个调用堆栈不变,如下所示:

Objective-C exceptions, as implemented by NSException, save their backtraces within the exception object right before the actual "throw" happens, as part of [NSException init] (or a similar initializer method). Unfortunately, C++ exceptions don't do the same. Normally, a C++ exception has a backtrace because the runtime library detects that there's no catch and immediately calls std::terminate, which in turn calls abort(), leaving the entire call stack intact, like so:

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,但此时调用堆栈反映了运行循环异常处理程序.

However, when the run loop exception handler traps the exception, execution resumes normally within the catch block. The original backtrace is therefore lost. The rethrow subsequently calls std::terminate, but at this point, the call stack reflects the run loop exception handler.

要在这种情况下从 C++ 异常中获取回溯,您必须抛出一个模仿 NSException 的异常对象,并将调用堆栈作为其构造函数的一部分读取,并确保抛出的所有异常在你的代码中做同样的事情.std::exception 不会这样做,而且您使用的任何第三方代码也不可能这样做.

To get a backtrace from a C++ exception in this circumstance, you have to throw an exception object which mimics NSException and reads the call stack as part of its constructor, and make sure that all exceptions thrown in your code do the same. std::exception doesn't do this, and it's not at all likely that any third-party code you're using will either.

向 Apple 提交一个错误,要求他们删除 CFRunLoop 异常处理程序,或者至少提供一个 API 来关闭它.目前没有 API,甚至没有 SPI 来执行此操作.

File a bug with Apple asking them to remove the CFRunLoop exception handler, or at least provide an API for shutting it off. There is no API, not even an SPI, for doing this right now.

这篇关于iOS:如何获取未处理的 std::exception 的堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆