打开Nil时如何拦截EXC_BAD_INSTRUCTION

我正在根据这篇博文建立一些基本的崩溃记录系统( 是的 ,我知道PLCRashReporter, ,我不能使用它,需要自己动手,无论多么有限。谢谢)。

我的代码注册了一个exception处理程序(带有NSSetUncaughtExceptionHandler() )和大多数信号的信号处理程序:

 SIGQUIT SIGILL SIGTRAP SIGABRT SIGEMT SIGFPE SIGBUS SIGSEGV SIGSYS SIGPIPE SIGALRM SIGXCPU SIGXFSZ 

它似乎与基本的Objective-C工作正常,例如“无法识别的选择器发送到实例……”等。


接下来,我尝试使用以下Swift代码:

 var empty:String! = nil let index = empty.startIndex // < KA-BOOM! 

…但抛出的exceptionEXC_BAD_INSTRUCTION未被捕获(我的处理程序未被调用),而是我熟悉了:

致命错误:在展开Optional值时意外发现nil

…在Xcode控制台中。

我错过了什么?

这个答案说这种运行时错误可以用SIGTRAP处理; 但是我已经在处理那个信号而且它似乎不起作用。


附录:似乎没有针对Swift运行时错误的集中式exception处理系统(越界,nil unwrap等); 看这篇文章 。 但是,Xcode仍然能够与EXC_BAD_INSTRUCTION崩溃,所以我的问题是:这怎么可能,为什么我的信号处理程序不能处理这个?


附录2:为了安全起见,我尝试为signal.h中定义的所有 20多个信号注册我的信号处理程序(不仅仅是上面列出的信号); 仍然没有变化。


附录3: Apple的官方文档了解和分析应用程序崩溃报告包含以下代码段:

跟踪陷阱[EXC_BREAKPOINT // SIGTRAP]

与exception退出类似,此exception旨在为附加的调试器提供在其执行的特定点中断进程的机会。 您可以使用__builtin_trap()函数从您自己的代码中触发此exception。 如果未附加调试器,则终止该过程并生成崩溃报告。

较低级别的库(例如,libdispatch)将在遇到致命错误时捕获该进程。 有关错误的其他信息可以在崩溃报告的“其他诊断信息”部分或设备的控制台中找到。

如果在运行时遇到意外情况,则Swift代码将以此exception类型终止,例如:

  • 具有nil值的非可选类型
  • 强制类型转换失败

查看Backtraces以确定遇到意外情况的位置。 其他信息也可能已记录到设备的控制台。 您应该修改崩溃位置的代码以正常处理运行时故障。 例如,使用Optional Binding而不是强制解包可选。

(强调我的)

仍然: 为什么我不能用我的SIGTRAP信号处理程序处理这个?

TL; DR: 附加调试器时,信号处理程序正常工作。


为了看看发生了什么,我建立了一个小型演示项目,我在其中注册了SIGUSR1的信号处理程序(可用的’用户定义’信号之一),然后使用kill()函数将所述信号发送到我的进程:

 kill(0, SIGUSR1); 

起初,我无法让Xcode的调试器跳转到我的信号处理程序,而是它会停在带有kill()调用的行,用我的问题中的红色突出显示它。

在阅读了这个问题及其答案之后 ,让我感到震惊的是,调试器必须非常依赖于信号,以便能够停止/恢复程序执行,例如在断点处。

使用其中一个答案中指定的符号断点:

 process handle SIGUSR1 -n true -p true -s false 

…我能够让Xcode停止在这个命令上:

 kill(pid, SIGUSR1); 

…而是在调试时跳转到我的信号处理程序。 我甚至可以进入信号处理程序并逐个执行它的语句; 从中显示警报视图等。

虽然我无法使用SIGTRAP (甚至SIGABRT )获得相同的结果,但是当我在没有连接调试器的情况下启动我的应用程序时(例如,通过点击),我的信号处理程序被调用(并且我的崩溃日志会保存到磁盘!)应用程序在主屏幕上的图标)并让它抛出一个Swift运行时错误,就像我在我的问题中提到的那样。


我猜测为什么我能够拦截unrecognized selector sent to instance...似乎是,作为一个Objective-Cexception ,它是与Unix信号完全不同的野兽,与调试器的工作无关(除非你为Objective-Cexception设置了一个exception断点?)。

使用不相关的函数NSSetUncaughtExceptionHandler()设置处理程序的事实应该是一个提示……

(我几乎是在谈论我的有限知识,所以请随意添加答案/评论,如你认为合适的更正)