简体   繁体   中英

NSSetUncaughtExceptionHandler doesn't work on mac

My code is here:

in myAppDelegate.m :

void catchException(NSException *e)
{
    NSLog( @"here is a exception");
}

@implementation myAppDelegate
{
    NSSetUncaughtExceptionHandler(&catchException);
    NSException *e = [[NSException alloc] initWithName: @"aException" reason: @"test" userInfo: nil];
    @throw e;
}

However the function catchException is never be trapped. Can anybody tell me why?

I have found in my own OSX code that I had to use NSExceptionHandler in order to reliably catch exceptions:

#import <Cocoa/Cocoa.h>
#import <ExceptionHandling/NSExceptionHandler.h>
#import "CocoaUtil.h"
#import <execinfo.h>

// ExceptionDelegate
@interface ExceptionDelegate : NSObject
@end
static ExceptionDelegate * _exceptionDelegate = nil;

int main(int argc, const char **argv) {
    int retval = 1;

    @autoreleasepool
    {
        //
        // Set exception handler delegate
        //
        _exceptionDelegate = [[ExceptionDelegate alloc] init];
        NSExceptionHandler *exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
        exceptionHandler.exceptionHandlingMask = NSLogAndHandleEveryExceptionMask;
        exceptionHandler.delegate = _exceptionDelegate;

        //
        // Set signal handling
        //
        int signals[] = {
            SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, SIGFPE, SIGBUS, SIGSEGV,
            SIGSYS, SIGPIPE, SIGALRM, SIGXCPU, SIGXFSZ
        };
        const unsigned numSignals = sizeof(signals) / sizeof(signals[0]);
        struct sigaction sa;
        sa.sa_sigaction = signalHandler;
        sa.sa_flags = SA_SIGINFO;
        sigemptyset(&sa.sa_mask);
        for (unsigned i = 0; i < numSignals; i++)
            sigaction(signals[i], &sa, NULL);


        // Do work

    }   // @autoreleasepool

    return retval;
}

static void dumpStack(void **frames, unsigned numFrames) {
    char **frameStrings = backtrace_symbols(frames, numFrames);
    if (frameStrings) {
        for (unsigned i = 0; i < numFrames && frameStrings[i] ; i++)
            logbareutf8((char *)frameStrings[i]);
        free(frameStrings);
    } else {
        logerr(@"No frames to dump");
    }
}

static void signalHandler(int sig, siginfo_t *info, void *context) {
    logerr(@"Caught signal %d", sig);

    const size_t maxFrames = 128;
    void *frames[maxFrames];
    unsigned numFrames = backtrace(frames, maxFrames);
    dumpStack(frames, numFrames);

    bool send = criticalAlertPanel(@"Application Error",
        @"Upload logfile to support site",
        @"MyApp is terminating due to signal %d", sig);
    if (send)
        sendLogfile();

    exit(102);
}

static void sendLogfile() {
    // Redacted
}

@implementation ExceptionDelegate

- (BOOL)exceptionHandler:(NSExceptionHandler *)exceptionHandler
      shouldLogException:(NSException *)exception
                    mask:(NSUInteger)mask {

    logerr(@"An unhandled %@ exception occurred: %@", [exception name], [exception reason]);

    // [exception callStackReturnAddresses] will be empty, so parse the NSStackTraceKey from
    // [exception userInfo].
    NSString *stackTrace = [[exception userInfo] objectForKey:NSStackTraceKey];
    NSScanner *scanner = [NSScanner scannerWithString:stackTrace];
    NSMutableArray *addresses = [[NSMutableArray alloc] initWithCapacity:0];
    NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    NSString *token;
    while ([scanner scanUpToCharactersFromSet:whitespace
                                   intoString:&token]) {
        [addresses addObject:token];
    }

    NSUInteger numFrames = [addresses count];
    if (numFrames > 0) {
        void **frames = (void **)malloc(sizeof(void *) * numFrames);
        NSUInteger i, parsedFrames;

        for (i = 0, parsedFrames = 0; i < numFrames; i++) {
            NSString *address = [addresses objectAtIndex:i];

            if (![CocoaUtil parseString:address toVoidPointer:&frames[parsedFrames]]) {
                logerr(@"Failed to parse frame address '%@'", address);
                break;
            }

            parsedFrames++;
        }

        if (parsedFrames > 0) {
            logerr(@"Stack trace:");
            dumpStack(frames, (unsigned)parsedFrames);
        }

        free(frames);
    } else {
        logerr(@"No addresses in stacktrace");
    }

    return YES;
}

- (BOOL)exceptionHandler:(NSExceptionHandler *)exceptionHandler
   shouldHandleException:(NSException *)exception
                    mask:(NSUInteger)mask {

    bool send = criticalAlertPanel(@"Application Error",
        @"Upload logfile to support site",
        @"MyApp is terminating due to an unhandled exception:\n\n%@",
        [exception reason]);
    if (send)
        sendLogfile();

    exit(101);

    // not reached
    return NO;
}

You'll need to import ExceptionHandling.framework as noted by trojanfoe.

Here is gist which cleans up the stack trace printing (some functions are missing):

https://gist.github.com/alfwatt/5ddfaf68e530a5a69e3d

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM