Home > Back-end >  Intercepting signals/mach exceptions in a C plugin on macOS
Intercepting signals/mach exceptions in a C plugin on macOS

Time:02-23

I'm working on a suite of plugins for a certain host application, targeting both Windows and Mac (OSX ). The plugins are written in C . I would like to add crash & exception report handling to them in case the plugin goes rogue. This in order to not bring the whole host app down in case the plugin misbehaves, but get some feedback instead and just skip that one plugin call (and making follow-up plugin calls a sort of no-op). Think logging some state and slapping an error code text on it. From then on the plugin switches into an error state where requesting details returns this state.

This is a big legacy code base which has been improved greatly over time, but there are still some rough edges here and there, so answers like "just don't crash" is not what I'm looking for :) It also doesn't help I'm much more of a Windows developer than a macOS developer, so I might have overlooked something completely obvious.

  • I've covered unhandled C exceptions in a cross-platform way by wrapping each host->plugin callback in a big C try/catch block right at the plugin entry points.
  • I'm also handling crashes, div-by-zero, access violations etc. for Windows at that same spot by using __try/__except and registering a SEH handler.
  • Now I want to do the latter as well for Mac. But here I'm struggling with finding out what my options are, if any.

I looked into signal handlers, but what I glean from that is that they are process-wide. I.e.: not plugin-friendly, especially when multiple of these plugins can be used by the host concurrently (who will catch and thus handle the signals first?). And the host app already has it's own crash handler, possibly using a signal handler, so installing our own would make it a fight over who's in charge I think? Plus that my reporting options are extremely limited in such handlers; if possible I'd like to have a bit more freedom here (like using std::strings with the new/delete they imply).

Then there's also Mach exception handling. But I totally fail to get informative results when googling this in combination with 'plugin'...

Does anyone have any advice on what route to go, or which option is better in my situation?

CodePudding user response:

The only options on macOS are signal handlers and Mach exception handlers.

Both of these mechanisms are process-wide, so would report problems wherever they occurred.

If a new signal handler is installed, the old one will not be run. The sigaction() API does return the previously installed one, so it's possible to have it run as well as your new one. Then again another signal handler might get installed and replace yours.

There's a very useful post here that goes into detail about implementing a signal handler - https://developer.apple.com/forums/thread/113742

The situation with Mach exception handlers is pretty much the same, calling task_set_exception_ports() will override the previously set handlers, so these have to be restored once your new handler has run if you want to propagate the exception. One big advantage of Mach exception handlers is that they can be run in a separate process, in which you're free to use std::strings etc. at the expense of it being more difficult to examine the crashed process's state.

There is little documentation around Mach exception handling, the best references are the various open-source crash reporting frameworks.

Overall it's difficult to properly implement crash detection, and I'd advise against doing it in a plugin. It's a LOT more complicated than SEH.

  • Related