OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/chrome_browser_application_mac.h" | 5 #import "chrome/browser/chrome_browser_application_mac.h" |
6 | 6 |
7 #import "base/logging.h" | 7 #import "base/logging.h" |
| 8 #import "base/mac/scoped_nsexception_enabler.h" |
8 #import "base/metrics/histogram.h" | 9 #import "base/metrics/histogram.h" |
9 #import "base/memory/scoped_nsobject.h" | 10 #import "base/memory/scoped_nsobject.h" |
10 #import "base/sys_string_conversions.h" | 11 #import "base/sys_string_conversions.h" |
11 #import "chrome/app/breakpad_mac.h" | 12 #import "chrome/app/breakpad_mac.h" |
12 #include "chrome/browser/accessibility/browser_accessibility_state.h" | 13 #include "chrome/browser/accessibility/browser_accessibility_state.h" |
13 #import "chrome/browser/app_controller_mac.h" | 14 #import "chrome/browser/app_controller_mac.h" |
14 #include "chrome/browser/ui/browser_list.h" | 15 #include "chrome/browser/ui/browser_list.h" |
15 #import "chrome/browser/ui/cocoa/objc_method_swizzle.h" | 16 #import "chrome/browser/ui/cocoa/objc_method_swizzle.h" |
16 #import "chrome/browser/ui/cocoa/objc_zombie.h" | 17 #import "chrome/browser/ui/cocoa/objc_zombie.h" |
17 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 if (aName == NSInvalidArgumentException) { | 87 if (aName == NSInvalidArgumentException) { |
87 fatal = YES; | 88 fatal = YES; |
88 } | 89 } |
89 | 90 |
90 // Dear reader: Something you just did provoked an NSException. | 91 // Dear reader: Something you just did provoked an NSException. |
91 // NSException is implemented in terms of setjmp()/longjmp(), | 92 // NSException is implemented in terms of setjmp()/longjmp(), |
92 // which does poor things when combined with C++ scoping | 93 // which does poor things when combined with C++ scoping |
93 // (destructors are skipped). Chrome should be NSException-free, | 94 // (destructors are skipped). Chrome should be NSException-free, |
94 // please check your backtrace and see if you can't file a bug | 95 // please check your backtrace and see if you can't file a bug |
95 // with a repro case. | 96 // with a repro case. |
96 if (fatal) { | 97 const bool allow = base::mac::GetNSExceptionsAllowed(); |
| 98 if (fatal && !allow) { |
97 LOG(FATAL) << "Someone is trying to raise an exception! " | 99 LOG(FATAL) << "Someone is trying to raise an exception! " |
98 << base::SysNSStringToUTF8(value); | 100 << base::SysNSStringToUTF8(value); |
99 } else { | 101 } else { |
100 // Make sure that developers see when their code throws | 102 // Make sure that developers see when their code throws |
101 // exceptions. | 103 // exceptions. |
102 DLOG(ERROR) << "Someone is trying to raise an exception! " | 104 DLOG(ERROR) << "Someone is trying to raise an exception! " |
103 << base::SysNSStringToUTF8(value); | 105 << base::SysNSStringToUTF8(value); |
104 NOTREACHED(); | 106 DCHECK(allow); |
105 } | 107 } |
106 } | 108 } |
107 | 109 |
108 // Forward to the original version. | 110 // Forward to the original version. |
109 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo); | 111 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo); |
110 } | 112 } |
111 @end | 113 @end |
112 | 114 |
113 namespace chrome_browser_application_mac { | 115 namespace chrome_browser_application_mac { |
114 | 116 |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 } else if ([sender isKindOfClass:[NSMenuItem class]]) { | 324 } else if ([sender isKindOfClass:[NSMenuItem class]]) { |
323 tag = [sender tag]; | 325 tag = [sender tag]; |
324 } | 326 } |
325 | 327 |
326 NSString* actionString = NSStringFromSelector(anAction); | 328 NSString* actionString = NSStringFromSelector(anAction); |
327 NSString* value = | 329 NSString* value = |
328 [NSString stringWithFormat:@"%@ tag %d sending %@ to %p", | 330 [NSString stringWithFormat:@"%@ tag %d sending %@ to %p", |
329 [sender className], tag, actionString, aTarget]; | 331 [sender className], tag, actionString, aTarget]; |
330 | 332 |
331 ScopedCrashKey key(kActionKey, value); | 333 ScopedCrashKey key(kActionKey, value); |
| 334 |
| 335 // Certain third-party code, such as print drivers, can still throw |
| 336 // exceptions and Chromium cannot fix them. This provides a way to |
| 337 // work around those on a spot basis. |
| 338 bool enableNSExceptions = false; |
| 339 |
| 340 // http://crbug.com/80686 , an Epson printer driver. |
| 341 if (anAction == @selector(selectPDE:)) { |
| 342 enableNSExceptions = true; |
| 343 } |
| 344 |
| 345 // Minimize the window by keeping this close to the super call. |
| 346 scoped_ptr<base::mac::ScopedNSExceptionEnabler> enabler(NULL); |
| 347 if (enableNSExceptions) |
| 348 enabler.reset(new base::mac::ScopedNSExceptionEnabler()); |
332 return [super sendAction:anAction to:aTarget from:sender]; | 349 return [super sendAction:anAction to:aTarget from:sender]; |
333 } | 350 } |
334 | 351 |
335 // NSExceptions which are caught by the event loop are logged here. | 352 // NSExceptions which are caught by the event loop are logged here. |
336 // NSException uses setjmp/longjmp, which can be very bad for C++, so | 353 // NSException uses setjmp/longjmp, which can be very bad for C++, so |
337 // we attempt to track and report them. | 354 // we attempt to track and report them. |
338 - (void)reportException:(NSException *)anException { | 355 - (void)reportException:(NSException *)anException { |
339 // If we throw an exception in this code, we can create an infinite | 356 // If we throw an exception in this code, we can create an infinite |
340 // loop. If we throw out of the if() without resetting | 357 // loop. If we throw out of the if() without resetting |
341 // |reportException|, we'll stop reporting exceptions for this run. | 358 // |reportException|, we'll stop reporting exceptions for this run. |
342 static BOOL reportingException = NO; | 359 static BOOL reportingException = NO; |
343 DCHECK(!reportingException); | 360 DCHECK(!reportingException); |
344 if (!reportingException) { | 361 if (!reportingException) { |
345 reportingException = YES; | 362 reportingException = YES; |
346 chrome_browser_application_mac::RecordExceptionWithUma(anException); | 363 chrome_browser_application_mac::RecordExceptionWithUma(anException); |
347 | 364 |
348 // http://crbug.com/45928 is a bug about needing to double-close | 365 // http://crbug.com/45928 is a bug about needing to double-close |
349 // windows sometimes. One theory is that |-isHandlingSendEvent| | 366 // windows sometimes. One theory is that |-isHandlingSendEvent| |
350 // gets latched to always return |YES|. Since scopers are used to | 367 // gets latched to always return |YES|. Since scopers are used to |
351 // manipulate that value, that should not be possible. One way to | 368 // manipulate that value, that should not be possible. One way to |
352 // sidestep scopers is setjmp/longjmp (see above). The following | 369 // sidestep scopers is setjmp/longjmp (see above). The following |
353 // is to "fix" this while the more fundamental concern is | 370 // is to "fix" this while the more fundamental concern is |
354 // addressed elsewhere. | 371 // addressed elsewhere. |
355 [self clearIsHandlingSendEvent]; | 372 [self clearIsHandlingSendEvent]; |
356 | 373 |
| 374 // If |ScopedNSExceptionEnabler| is used to allow exceptions, and an |
| 375 // uncaught exception is thrown, it will throw past all of the scopers. |
| 376 // Reset the flag so that future exceptions are not masked. |
| 377 base::mac::SetNSExceptionsAllowed(false); |
| 378 |
357 // Store some human-readable information in breakpad keys in case | 379 // Store some human-readable information in breakpad keys in case |
358 // there is a crash. Since breakpad does not provide infinite | 380 // there is a crash. Since breakpad does not provide infinite |
359 // storage, we track two exceptions. The first exception thrown | 381 // storage, we track two exceptions. The first exception thrown |
360 // is tracked because it may be the one which caused the system to | 382 // is tracked because it may be the one which caused the system to |
361 // go off the rails. The last exception thrown is tracked because | 383 // go off the rails. The last exception thrown is tracked because |
362 // it may be the one most directly associated with the crash. | 384 // it may be the one most directly associated with the crash. |
363 static NSString* const kFirstExceptionKey = @"firstexception"; | 385 static NSString* const kFirstExceptionKey = @"firstexception"; |
364 static BOOL trackedFirstException = NO; | 386 static BOOL trackedFirstException = NO; |
365 static NSString* const kLastExceptionKey = @"lastexception"; | 387 static NSString* const kLastExceptionKey = @"lastexception"; |
366 | 388 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 if (RenderViewHost* rvh = contents->render_view_host()) { | 421 if (RenderViewHost* rvh = contents->render_view_host()) { |
400 rvh->EnableRendererAccessibility(); | 422 rvh->EnableRendererAccessibility(); |
401 } | 423 } |
402 } | 424 } |
403 } | 425 } |
404 } | 426 } |
405 return [super accessibilitySetValue:value forAttribute:attribute]; | 427 return [super accessibilitySetValue:value forAttribute:attribute]; |
406 } | 428 } |
407 | 429 |
408 @end | 430 @end |
OLD | NEW |