xref: /aosp_15_r20/external/google-breakpad/src/client/mac/testapp/Controller.m (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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
261