michael@0: // Copyright (c) 2006, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #import michael@0: michael@0: #import "Controller.h" michael@0: #import "TestClass.h" michael@0: #import "GTMDefines.h" michael@0: #include michael@0: #include michael@0: michael@0: @implementation Controller michael@0: michael@0: - (void)causeCrash { michael@0: float *aPtr = nil; michael@0: NSLog(@"Crash!"); michael@0: NSLog(@"Bad programmer: %f", *aPtr); michael@0: } michael@0: michael@0: - (void)generateReportWithoutCrash:(id)sender { michael@0: BreakpadGenerateAndSendReport(breakpad_); michael@0: } michael@0: michael@0: - (IBAction)showForkTestWindow:(id) sender { michael@0: [forkTestOptions_ setIsVisible:YES]; michael@0: } michael@0: michael@0: - (IBAction)forkTestOptions:(id)sender { michael@0: NSInteger tag = [[sender selectedCell] tag]; michael@0: NSLog(@"sender tag: %d", tag); michael@0: if (tag <= 2) { michael@0: bpForkOption = tag; michael@0: } michael@0: michael@0: if (tag == 3) { michael@0: useVFork = NO; michael@0: } michael@0: michael@0: if (tag == 4) { michael@0: useVFork = YES; michael@0: } michael@0: michael@0: if (tag >= 5 && tag <= 7) { michael@0: progCrashPoint = tag; michael@0: } michael@0: michael@0: } michael@0: michael@0: - (IBAction)forkTestGo:(id)sender { michael@0: michael@0: NSString *resourcePath = [[NSBundle bundleForClass: michael@0: [self class]] resourcePath]; michael@0: NSString *execProgname = nil; michael@0: if (progCrashPoint == DURINGLAUNCH) { michael@0: execProgname = [resourcePath stringByAppendingString:@"/crashduringload"]; michael@0: } else if (progCrashPoint == AFTERLAUNCH) { michael@0: execProgname = [resourcePath stringByAppendingString:@"/crashInMain"]; michael@0: } michael@0: michael@0: const char *progName = NULL; michael@0: if (progCrashPoint != BETWEENFORKEXEC) { michael@0: progName = [execProgname UTF8String]; michael@0: } michael@0: michael@0: int pid; michael@0: michael@0: if (bpForkOption == UNINSTALL) { michael@0: BreakpadRelease(breakpad_); michael@0: } michael@0: michael@0: if (useVFork) { michael@0: pid = vfork(); michael@0: } else { michael@0: pid = fork(); michael@0: } michael@0: michael@0: if (pid == 0) { michael@0: sleep(3); michael@0: NSLog(@"Child continuing"); michael@0: FILE *fd = fopen("/tmp/childlog.txt","wt"); michael@0: kern_return_t kr; michael@0: if (bpForkOption == RESETEXCEPTIONPORT) { michael@0: kr = task_set_exception_ports(mach_task_self(), michael@0: EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | michael@0: EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT, michael@0: MACH_PORT_NULL, michael@0: EXCEPTION_DEFAULT, michael@0: THREAD_STATE_NONE); michael@0: fprintf(fd,"task_set_exception_ports returned %d\n", kr); michael@0: } michael@0: michael@0: if (progCrashPoint == BETWEENFORKEXEC) { michael@0: fprintf(fd,"crashing post-fork\n"); michael@0: int *a = NULL; michael@0: printf("%d\n",*a++); michael@0: } michael@0: michael@0: fprintf(fd,"about to call exec with %s\n", progName); michael@0: fclose(fd); michael@0: int i = execl(progName, progName, NULL); michael@0: fprintf(fd, "exec returned! %d\n", i); michael@0: fclose(fd); michael@0: } michael@0: } michael@0: michael@0: - (IBAction)crash:(id)sender { michael@0: NSInteger tag = [sender tag]; michael@0: michael@0: if (tag == 1) { michael@0: [NSObject cancelPreviousPerformRequestsWithTarget:self]; michael@0: [self performSelector:@selector(causeCrash) withObject:nil afterDelay:10.0]; michael@0: [sender setState:NSOnState]; michael@0: return; michael@0: } michael@0: michael@0: if (tag == 2 && breakpad_) { michael@0: BreakpadRelease(breakpad_); michael@0: breakpad_ = NULL; michael@0: return; michael@0: } michael@0: michael@0: [self causeCrash]; michael@0: } michael@0: michael@0: - (void)anotherThread { michael@0: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; michael@0: TestClass *tc = [[TestClass alloc] init]; michael@0: michael@0: [tc wait]; michael@0: michael@0: [pool release]; michael@0: } michael@0: michael@0: - (void)awakeFromNib { michael@0: NSBundle *bundle = [NSBundle mainBundle]; michael@0: NSDictionary *info = [bundle infoDictionary]; michael@0: michael@0: michael@0: breakpad_ = BreakpadCreate(info); michael@0: michael@0: // Do some unit tests with keys michael@0: // first a series of bogus values michael@0: BreakpadSetKeyValue(breakpad_, nil, @"bad2"); michael@0: BreakpadSetKeyValue(nil, @"bad3", @"bad3"); michael@0: michael@0: // Now some good ones michael@0: BreakpadSetKeyValue(breakpad_,@"key1", @"value1"); michael@0: BreakpadSetKeyValue(breakpad_,@"key2", @"value2"); michael@0: BreakpadSetKeyValue(breakpad_,@"key3", @"value3"); michael@0: michael@0: // Look for a bogus one that we didn't try to set michael@0: NSString *test = BreakpadKeyValue(breakpad_, @"bad4"); michael@0: if (test) { michael@0: NSLog(@"Bad BreakpadKeyValue (bad4)"); michael@0: } michael@0: michael@0: // Look for a bogus one we did try to set michael@0: test = BreakpadKeyValue(breakpad_, @"bad1"); michael@0: if (test) { michael@0: NSLog(@"Bad BreakpadKeyValue (bad1)"); michael@0: } michael@0: michael@0: // Test some bad args for BreakpadKeyValue michael@0: test = BreakpadKeyValue(nil, @"bad5"); michael@0: if (test) { michael@0: NSLog(@"Bad BreakpadKeyValue (bad5)"); michael@0: } michael@0: michael@0: test = BreakpadKeyValue(breakpad_, nil); michael@0: if (test) { michael@0: NSLog(@"Bad BreakpadKeyValue (nil)"); michael@0: } michael@0: michael@0: // Find some we did set michael@0: test = BreakpadKeyValue(breakpad_, @"key1"); michael@0: if (![test isEqualToString:@"value1"]) { michael@0: NSLog(@"Can't find BreakpadKeyValue (key1)"); michael@0: } michael@0: test = BreakpadKeyValue(breakpad_, @"key2"); michael@0: if (![test isEqualToString:@"value2"]) { michael@0: NSLog(@"Can't find BreakpadKeyValue (key2)"); michael@0: } michael@0: test = BreakpadKeyValue(breakpad_, @"key3"); michael@0: if (![test isEqualToString:@"value3"]) { michael@0: NSLog(@"Can't find BreakpadKeyValue (key3)"); michael@0: } michael@0: michael@0: // Bad args for BreakpadRemoveKeyValue michael@0: BreakpadRemoveKeyValue(nil, @"bad6"); michael@0: BreakpadRemoveKeyValue(breakpad_, nil); michael@0: michael@0: // Remove one that is valid michael@0: BreakpadRemoveKeyValue(breakpad_, @"key3"); michael@0: michael@0: // Try and find it michael@0: test = BreakpadKeyValue(breakpad_, @"key3"); michael@0: if (test) { michael@0: NSLog(@"Shouldn't find BreakpadKeyValue (key3)"); michael@0: } michael@0: michael@0: // Try and remove it again michael@0: BreakpadRemoveKeyValue(breakpad_, @"key3"); michael@0: michael@0: // Try removal by setting to nil michael@0: BreakpadSetKeyValue(breakpad_,@"key2", nil); michael@0: // Try and find it michael@0: test = BreakpadKeyValue(breakpad_, @"key2"); michael@0: if (test) { michael@0: NSLog(@"Shouldn't find BreakpadKeyValue (key2)"); michael@0: } michael@0: michael@0: BreakpadAddUploadParameter(breakpad_, michael@0: @"MeaningOfLife", michael@0: @"42"); michael@0: [NSThread detachNewThreadSelector:@selector(anotherThread) michael@0: toTarget:self withObject:nil]; michael@0: michael@0: NSUserDefaults *args = [NSUserDefaults standardUserDefaults]; michael@0: michael@0: // If the user specified autocrash on the command line, toggle michael@0: // Breakpad to not confirm and crash immediately. This is for michael@0: // automated testing. michael@0: if ([args boolForKey:@"autocrash"]) { michael@0: BreakpadSetKeyValue(breakpad_, michael@0: @BREAKPAD_SKIP_CONFIRM, michael@0: @"YES"); michael@0: [self causeCrash]; michael@0: } michael@0: michael@0: progCrashPoint = DURINGLAUNCH; michael@0: [window_ center]; michael@0: [window_ makeKeyAndOrderFront:self]; michael@0: } michael@0: michael@0: @end