How to Configure Custom Exception Handling with MulleObjCSetupExceptionHandler in Mulle-ObjC
Call MulleObjCSetupExceptionHandler with a function pointer to install a thread-local uncaught exception handler that the Mulle-ObjC runtime invokes when MulleObjCRaiseException propagates uncaught.
The Mulle-ObjC runtime provides a lightweight, thread-safe mechanism for handling uncaught exceptions through the MulleObjCSetupExceptionHandler function. Unlike traditional Objective-C runtimes that rely on global handlers, Mulle-ObjC stores exception handlers per-thread within the universal runtime structure, allowing fine-grained control over error recovery and logging strategies in the mulle-objc/mulleobjc repository.
Understanding the Exception Handler API
Core Function Signature
The primary interface is declared in src/function/MulleObjCExceptionHandler.h. The function accepts a single parameter: a pointer to a handler function that matches the signature void handler(void).
void MulleObjCSetupExceptionHandler(void (*handler)(void));
When you pass a non-NULL function pointer, the runtime stores that address in the current thread's universe structure (struct _mulle_objc_universe). Passing NULL effectively removes any previously installed handler for that thread.
Thread-Local Storage Architecture
The handler is stored on a per-thread basis, not globally. This design ensures that different threads can maintain independent exception handling strategies without interfering with each other. Each thread must invoke MulleObjCSetupExceptionHandler independently if it requires custom handling; otherwise, uncaught exceptions in that thread will cause immediate process termination.
Installing a Custom Exception Handler
Basic Implementation Pattern
To configure handling, define a callback function and register it at thread startup. The handler should perform cleanup or logging, then terminate, because the runtime does not resume execution after the handler returns.
#include "src/function/MulleObjCExceptionHandler.h"
#include <stdio.h>
#include <stdlib.h>
/* Custom handler invoked when an exception is not caught */
static void my_exception_handler(void)
{
fprintf(stderr, "[ERROR] Uncaught exception detected. Performing cleanup...\n");
/* Insert resource cleanup or crash reporting here */
abort(); /* Terminate to prevent undefined behavior */
}
int main(void)
{
/* Install handler for the main thread */
MulleObjCSetupExceptionHandler(my_exception_handler);
/* Application code proceeds... */
return 0;
}
NS-Style Wrapper Functions
For compatibility with conventional Objective-C patterns, the header also provides NSSetUncaughtExceptionHandler and NSGetUncaughtExceptionHandler, which act as thin wrappers around the core MulleObjCSetupExceptionHandler mechanism. These wrappers access the same underlying thread-local storage slot.
/* Equivalent to MulleObjCSetupExceptionHandler(my_handler); */
NSSetUncaughtExceptionHandler(my_exception_handler);
/* Retrieve the currently installed handler */
void (*current_handler)(void) = NSGetUncaughtExceptionHandler();
Raising Exceptions and Handler Invocation
The Exception Propagation Flow
When code calls MulleObjCRaiseException(id exception), the runtime unwinds the stack searching for a catch handler. If no catch block intercepts the exception, the runtime checks for an installed handler in the current thread's universe structure. If present, it invokes that handler; otherwise, it terminates the process immediately without additional logging.
Practical Raising Example
The following example demonstrates raising an exception that triggers the custom handler installed via MulleObjCSetupExceptionHandler.
#include "src/function/MulleObjCExceptionHandler.h"
#include <stdio.h>
#include <stdlib.h>
static void log_and_abort_handler(void)
{
fprintf(stderr, ">>> Handler invoked: uncaught exception reached top of stack\n");
abort();
}
static void risky_operation(void)
{
id exception = (id)"CriticalFailure";
MulleObjCRaiseException(exception); /* Will trigger handler if uncaught */
}
int main(void)
{
MulleObjCSetupExceptionHandler(log_and_abort_handler);
/* This call raises an exception that propagates uncaught */
risky_operation();
/* Execution never reaches here */
return 0;
}
Key Source Files and Documentation
The implementation and API contracts reside in specific files within the repository:
src/function/MulleObjCExceptionHandler.h: DeclaresMulleObjCSetupExceptionHandler,MulleObjCRaiseException, and the NS-style wrapper functions.dox/API_MulleObjCExceptionHandler.md: Contains comprehensive API documentation describing the setup function, raising semantics, and thread-local behavior.
Summary
MulleObjCSetupExceptionHandlerinstalls a thread-local callback for uncaught exceptions by storing the function pointer in the runtime universe structure.- Handlers are thread-local; each thread must configure its own handler independently.
- Use
MulleObjCRaiseExceptionto signal errors that may trigger the custom handler if allowed to propagate uncaught. - NSSetUncaughtExceptionHandler provides a familiar Objective-C wrapper around the native Mulle-ObjC API.
- Custom handlers must terminate the process (e.g., via
abort()) to prevent undefined behavior, as the runtime does not resume normal execution after handler invocation.
Frequently Asked Questions
What function signature is required for MulleObjCSetupExceptionHandler?
The function expects a pointer to a callback with the signature void handler(void), taking no parameters and returning no value. This minimal signature keeps the handler lightweight while allowing you to access thread-local storage or global state internally if needed.
Is the exception handler global or thread-local?
The handler is thread-local. According to the implementation in src/function/MulleObjCExceptionHandler.h, the runtime stores the handler pointer within the per-thread universe structure. Each thread must call MulleObjCSetupExceptionHandler independently to configure its own handling strategy.
How does MulleObjCRaiseException interact with the custom handler?
When MulleObjCRaiseException(id exception) is called and the exception propagates uncaught to the top of the stack, the runtime checks the current thread's handler slot. If MulleObjCSetupExceptionHandler was called for that thread, the runtime invokes the stored function; otherwise, it terminates the process immediately.
Can I use NSSetUncaughtExceptionHandler instead of the MulleObjC prefix?
Yes. The header provides NSSetUncaughtExceptionHandler as a thin wrapper around MulleObjCSetupExceptionHandler, offering a familiar API for developers transitioning from other Objective-C runtimes. Both functions manipulate the same underlying thread-local handler slot.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →