如何为 EXC_BAD_ACCESS 崩溃设置新的 handler/responder

How to set a new handler/responder for EXC_BAD_ACCESS crashes

我正在寻找为 EXC_BAD_ACCESS 覆盖 responder/handler 的方法。这就是我为 signal 崩溃或 NSException 设置处理程序的方式,它工作正常:

NSSetUncaughtExceptionHandler(newExceptionHandler)
signal(SIGABRT, newSignalHandler)
signal(SIGILL, newSignalHandler)

我试过了,但没有被调用:

signal(EXC_BAD_ACCESS, newSignalHandler)

有什么想法吗?

如果您没有使用现有的崩溃报告器(它们很难自己编写,在处理损坏的内存等时),您可能会查看它们的来源以了解它们正在处理哪些信号。例如,PLCrashReporter's PLCrashReporter.m hooks onto SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, and SIGTRAP, which seems to be the usual list for crash handlers. EXC_BAD_ACCESS should turn into either SIGBUS or SIGSEGV. Writing re-entrant code correctly in signal handlers is extremely difficult(不能使用任何 ObjC 或其中的大多数 C API),所以要小心——尽管我猜如果你已经崩溃了,也不会造成更多伤害。但是你越小心,你处理的异常就越多而不会进一步崩溃。

正如 Carl 提到的那样,由于各种原因,拦截 iOS(和 macOS)上的崩溃事件充满了危险。我有一段时间是 Crashlytics SDK 的维护者,我强烈建议不要这样做。

但是,这绝对是可能的。

信号、异常(ObjC 或 C++)和 mach 异常之间的关系似乎让人们很困惑。这些都是非常不同的东西。

在 iOS(和 tvOS、macOS)上,终止进程的事件是 mach 异常。实际上,这些是您可以拦截的低级事件。当您看到 EXC_ 前缀时,您知道您正在查看 mach 异常。我相信这些都在 mach/exception.h.

中定义

现在,iOS 有一个有趣的实现,如果没有 mach 异常处理程序,OS 会将事件转换为 unix 信号。 signal 函数可用于拦截这些。由于 EXC_BAD_ACCESS 不是 unix 信号,因此它不是 signal 函数的有效参数。但是,您可以向列出的那些信号添加处理程序,它们会为您提供大致相同的信息。

Mach 异常是一种更强大、更安全的拦截此类事件的机制。不幸的是,它们还需要复杂得多的处理系统。信号有各种各样的问题,但是用起来简单多了。

我很想知道你想做什么,以防万一有更好的方法来实现你所追求的目标。

同样,我会避免走这条路。这不值得你花时间。让事情正常运转是很有挑战性的,当你这样做的时候,你会陷入一种虚假的安全感。您甚至可能认为一切正常,因为您的代码有时会完全出错,您永远不会知道,您只会时不时地从随机挂起的用户那里收到奇怪的报告。