Exception Handling Library [EXPERIMENTAL]

I’ve been working on an experimental library that implements Try/Catch. I started with the CException library. There are some serious caveats to such a thing, since it’s not really possible to unwind the stack as C++ exceptions would. That said, for a more advanced user, it could be useful. The API is the same as CException, plus a few things specific to implementing for Particle (and minus a few things, too, such as the separate config include)

Perhaps more interestingly, the library also includes an experimental hardware fault handler that allows a hardware exception to be “caught” as well. Obviously in many cases there won’t be enough functional system left by the time a hardware exception occurs to have anything to throw the exception to or to be able to actually call the logger, but in many other cases there could be. If the fault can be recovered from, the library logs the hardware exception data and throws an exception. The handler must be activated by calling CEXCEPTION_ACTIVATE_HW_HANDLERS(), either in setup() or somewhere in STARTUP().

Currently it only works on threaded platforms. On threaded platforms, creating a new thread that will participate in exception handling requires using the provided NEW_THREAD() and END_THREAD() macros to properly register the thread with the library. The NEW_THREAD() parameter list is the same as the os_thread_create() parameters, plus one more at the end for an optional unhandled exception callback; if an unhandled exception occurs in a thread created with the NEW_THREAD() macro, the thread will be terminated and optionally a callback called. Threads created with new Thread() cannot currently participate in exception handling. By default, the library is set up for one thread. To register more threads, first call CEXCEPTION_SET_NUM_THREADS(num).

I’m working on adding some interesting examples (and some detail to the one that’s there already). There is a full test suite (uses unit-test.h from the firmware tests). (I’ve only tested against Photon at the moment)

Lastly, the library requires at least firmware 0.6.0-rc1 because it uses the new logging feature.

CException-Particle Library on GitHub

At this point the library is experimental…but if this sort of thing interests you, feedback is welcome! I haven’t yet set it up as a Web IDE library, so to mess around you’ll have to build local. If/when it’s a little less experimental, I will add it.

Also here’s a rather windy article I wrote while working through some of the gritty hardware details. It talks about how the hardware exception handling works.
ARM Cortex M3: Recovering from a Hard Fault.md

2 Likes

Nice work!

You mentioned call stack unwinds aren’t possible. What if the user instrumented all their functions such that on entry the function name were pushed to a global array (with sufficient space reserved in advance for a reasonable call depth), and popped on exit? I implemented a try/catch framework for Visual Basic a long time ago which built on this approach. It even included an IDE plugin which would “wrap” or “unwrap” functions (including all exit points) with the appropriate boilerplates at the click of a button (so you could easily switch between “for compiling” and “for friendly human editing”) and did some extras like adding line numbers etc (so exceptions could be traced to the exact line which caused them). We used it at scale in a commercial product and it worked like a champ. Better, in fact, than several popular - yet surprisingly buggy - commercially available error handling libraries we tried beforehand (and those cost thousands of dollars per developer seat).

You wouldn’t get things like local variable value inspection, but you would get a full stack trace of function names, for a wee bit of code- and memory-overhead. Short, simple functions that are provably error-free and need to squeeze out every last cycle of performance could opt out of the mechanism.

BTW could you elaborate on what necessitated threading? Was this not able to be achieved via a synchronous interrupt handler? I’m not being skeptical, I’m just curious.

1 Like

The application I was working on had 128x64 display, some VS1053B MP3 ICs, an SD card, some buttons, and a low-speed serial interface (MIDI) that was used to clock other equipment. All of this stuff could have been done with interrupts, but it was more fun using threads because it was new stuff that I got to learn. The clocking was interrupt-driven for precision, and then there were separate threads for UI, input, state management, and audio playback.

Your approach would certainly work for instrumenting purposes! The caveat still applies that combining it with C++ will make messes, because while you can throw and catch exceptions and know what functions are on the stack, you still will lack the complete stack unwinding information needed to correctly clean up automatic C++ variables. If your exception bubbles across stack frames, C++ destructors will not be called. It would be fine to use for operational use in plain C programs (that’s what the folks who wrote CException library wrote it for). I suppose it would also be valid to panic if an exception was thrown across frames.