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