Created
June 17, 2011 22:51
-
-
Save landonf/1032539 to your computer and use it in GitHub Desktop.
Explanation of why backtrace(3) and stack overflow don't mix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <pthread.h> | |
#import <execinfo.h> | |
#import <string.h> | |
#import <stdint.h> | |
/* | |
* A signal handler that is broken in two ways: | |
* 1) The handler calls APIs that are not declared to be async-safe and may deadlock or otherwise fail. | |
* 2) The handler can not capture a backtrace should the stack overflow. | |
*/ | |
static void unsafe_signal_handler (int signo) { | |
signal(signo, SIG_DFL); | |
/* Attempt to use backtrace(3) to fetch the backtrace. This requires that we be | |
* operating on the crashed thread's stack, but that stack just overflowed, | |
* and our signal handler will simply crash. | |
* | |
* However, if we used sigaltstack() to correctly run on a different stack, our | |
* backtrace would be empty! This is not limited to backtrace(3) -- [NSThread callStackReturnAddresses] | |
* will exhibit the same behavior. | |
* | |
* This is one reason why backtraces must be implemented by implementing your own stack walking | |
* using the ucontext_t from the SA_SIGINFO prototype. | |
*/ | |
void *callstack[128]; | |
int count = backtrace(callstack, 128); | |
backtrace_symbols_fd(callstack, count, STDERR_FILENO); | |
} | |
int main(int argc, char *argv[]) { | |
NSAutoreleasePool *pool = [NSAutoreleasePool new]; | |
/* Set up the signal handler. */ | |
signal(SIGABRT, unsafe_signal_handler); | |
signal(SIGSEGV, unsafe_signal_handler); | |
/* Run some buggy code in an unusual code path. A small typo will trigger infinite recursion ... */ | |
NSArray *resultMessages = [NSMutableArray arrayWithObject: @"Error message!"]; | |
NSMutableArray *results = [[NSMutableArray alloc] init]; | |
for (NSObject *result in resultMessages) | |
[results addObject: results]; // Whoops! | |
NSLog(@"Some strange unexpected error we never see occured with results: %@", results); | |
[pool drain]; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment