Home | History | Annotate | Download | only in testapp
      1 // Copyright (c) 2006, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #import <Breakpad/Breakpad.h>
     31 
     32 #import "Controller.h"
     33 #import "TestClass.h"
     34 #import "GTMDefines.h"
     35 #include <unistd.h>
     36 #include <mach/mach.h>
     37 
     38 @implementation Controller
     39 
     40 - (void)causeCrash {
     41   float *aPtr = nil;
     42   NSLog(@"Crash!");
     43   NSLog(@"Bad programmer: %f", *aPtr);
     44 }
     45 
     46 - (void)generateReportWithoutCrash:(id)sender {
     47   BreakpadGenerateAndSendReport(breakpad_);
     48 }
     49 
     50 - (IBAction)showForkTestWindow:(id) sender {
     51   [forkTestOptions_ setIsVisible:YES];
     52 }
     53 
     54 - (IBAction)forkTestOptions:(id)sender {
     55   NSInteger tag = [[sender selectedCell] tag];
     56   NSLog(@"sender tag: %d", tag);
     57   if (tag <= 2) {
     58     bpForkOption = tag;
     59   }
     60 
     61   if (tag == 3) {
     62     useVFork = NO;
     63   }
     64 
     65   if (tag == 4) {
     66     useVFork = YES;
     67   }
     68 
     69   if (tag >= 5 && tag <= 7) {
     70     progCrashPoint = tag;
     71   }
     72 
     73 }
     74 
     75 - (IBAction)forkTestGo:(id)sender {
     76 
     77   NSString *resourcePath = [[NSBundle bundleForClass:
     78                                         [self class]] resourcePath];
     79   NSString *execProgname = nil;
     80   if (progCrashPoint == DURINGLAUNCH) {
     81     execProgname = [resourcePath stringByAppendingString:@"/crashduringload"];
     82   } else if (progCrashPoint == AFTERLAUNCH) {
     83     execProgname = [resourcePath stringByAppendingString:@"/crashInMain"];
     84   }
     85 
     86   const char *progName = NULL;
     87   if (progCrashPoint != BETWEENFORKEXEC) {
     88     progName = [execProgname UTF8String];
     89   }
     90 
     91   int pid;
     92 
     93   if (bpForkOption == UNINSTALL) {
     94     BreakpadRelease(breakpad_);
     95   }
     96 
     97   if (useVFork) {
     98     pid = vfork();
     99   } else {
    100     pid = fork();
    101   }
    102 
    103   if (pid == 0) {
    104     sleep(3);
    105     NSLog(@"Child continuing");
    106     FILE *fd = fopen("/tmp/childlog.txt","wt");
    107     kern_return_t kr;
    108     if (bpForkOption == RESETEXCEPTIONPORT) {
    109       kr = task_set_exception_ports(mach_task_self(),
    110                                EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION |
    111                                EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT,
    112                                MACH_PORT_NULL,
    113                                EXCEPTION_DEFAULT,
    114                                THREAD_STATE_NONE);
    115       fprintf(fd,"task_set_exception_ports returned %d\n", kr);
    116     }
    117 
    118     if (progCrashPoint == BETWEENFORKEXEC) {
    119       fprintf(fd,"crashing post-fork\n");
    120       int *a = NULL;
    121       printf("%d\n",*a++);
    122     }
    123 
    124     fprintf(fd,"about to call exec with %s\n", progName);
    125     fclose(fd);
    126     int i = execl(progName, progName, NULL);
    127     fprintf(fd, "exec returned! %d\n", i);
    128     fclose(fd);
    129   }
    130 }
    131 
    132 - (IBAction)crash:(id)sender {
    133   NSInteger tag = [sender tag];
    134 
    135   if (tag == 1) {
    136     [NSObject cancelPreviousPerformRequestsWithTarget:self];
    137     [self performSelector:@selector(causeCrash) withObject:nil afterDelay:10.0];
    138     [sender setState:NSOnState];
    139     return;
    140   }
    141 
    142   if (tag == 2 && breakpad_) {
    143     BreakpadRelease(breakpad_);
    144     breakpad_ = NULL;
    145     return;
    146   }
    147 
    148   [self causeCrash];
    149 }
    150 
    151 - (void)anotherThread {
    152   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    153   TestClass *tc = [[TestClass alloc] init];
    154 
    155   [tc wait];
    156 
    157   [pool release];
    158 }
    159 
    160 - (void)awakeFromNib {
    161   NSBundle *bundle = [NSBundle mainBundle];
    162   NSDictionary *info = [bundle infoDictionary];
    163 
    164 
    165   breakpad_ = BreakpadCreate(info);
    166 
    167   // Do some unit tests with keys
    168   // first a series of bogus values
    169   BreakpadSetKeyValue(breakpad_, nil, @"bad2");
    170   BreakpadSetKeyValue(nil, @"bad3", @"bad3");
    171 
    172   // Now some good ones
    173   BreakpadSetKeyValue(breakpad_,@"key1", @"value1");
    174   BreakpadSetKeyValue(breakpad_,@"key2", @"value2");
    175   BreakpadSetKeyValue(breakpad_,@"key3", @"value3");
    176 
    177   // Look for a bogus one that we didn't try to set
    178   NSString *test = BreakpadKeyValue(breakpad_, @"bad4");
    179   if (test) {
    180     NSLog(@"Bad BreakpadKeyValue (bad4)");
    181   }
    182 
    183   // Look for a bogus one we did try to set
    184   test = BreakpadKeyValue(breakpad_, @"bad1");
    185   if (test) {
    186     NSLog(@"Bad BreakpadKeyValue (bad1)");
    187   }
    188 
    189   // Test some bad args for BreakpadKeyValue
    190   test = BreakpadKeyValue(nil, @"bad5");
    191   if (test) {
    192     NSLog(@"Bad BreakpadKeyValue (bad5)");
    193   }
    194 
    195   test = BreakpadKeyValue(breakpad_, nil);
    196   if (test) {
    197     NSLog(@"Bad BreakpadKeyValue (nil)");
    198   }
    199 
    200   // Find some we did set
    201   test = BreakpadKeyValue(breakpad_, @"key1");
    202   if (![test isEqualToString:@"value1"]) {
    203     NSLog(@"Can't find BreakpadKeyValue (key1)");
    204   }
    205   test = BreakpadKeyValue(breakpad_, @"key2");
    206   if (![test isEqualToString:@"value2"]) {
    207     NSLog(@"Can't find BreakpadKeyValue (key2)");
    208   }
    209   test = BreakpadKeyValue(breakpad_, @"key3");
    210   if (![test isEqualToString:@"value3"]) {
    211     NSLog(@"Can't find BreakpadKeyValue (key3)");
    212   }
    213 
    214   // Bad args for BreakpadRemoveKeyValue
    215   BreakpadRemoveKeyValue(nil, @"bad6");
    216   BreakpadRemoveKeyValue(breakpad_, nil);
    217 
    218   // Remove one that is valid
    219   BreakpadRemoveKeyValue(breakpad_, @"key3");
    220 
    221   // Try and find it
    222   test = BreakpadKeyValue(breakpad_, @"key3");
    223   if (test) {
    224     NSLog(@"Shouldn't find BreakpadKeyValue (key3)");
    225   }
    226 
    227   // Try and remove it again
    228   BreakpadRemoveKeyValue(breakpad_, @"key3");
    229 
    230   // Try removal by setting to nil
    231   BreakpadSetKeyValue(breakpad_,@"key2", nil);
    232   // Try and find it
    233   test = BreakpadKeyValue(breakpad_, @"key2");
    234   if (test) {
    235     NSLog(@"Shouldn't find BreakpadKeyValue (key2)");
    236   }
    237 
    238   BreakpadAddUploadParameter(breakpad_,
    239                              @"MeaningOfLife",
    240                              @"42");
    241   [NSThread detachNewThreadSelector:@selector(anotherThread)
    242                            toTarget:self withObject:nil];
    243 
    244   NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
    245 
    246   // If the user specified autocrash on the command line, toggle
    247   // Breakpad to not confirm and crash immediately.  This is for
    248   // automated testing.
    249   if ([args boolForKey:@"autocrash"]) {
    250     BreakpadSetKeyValue(breakpad_,
    251                         @BREAKPAD_SKIP_CONFIRM,
    252                         @"YES");
    253     [self causeCrash];
    254   }
    255 
    256   progCrashPoint = DURINGLAUNCH;
    257   [window_ center];
    258   [window_ makeKeyAndOrderFront:self];
    259 }
    260 
    261 @end
    262