Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/auto_reset.h" | 7 #import "base/auto_reset.h" |
| 8 #include "base/debug/crash_logging.h" | 8 #include "base/debug/crash_logging.h" |
| 9 #include "base/debug/stack_trace.h" | 9 #include "base/debug/stack_trace.h" |
| 10 #import "base/logging.h" | 10 #import "base/logging.h" |
| 11 #import "base/mac/scoped_nsexception_enabler.h" | 11 #import "base/mac/scoped_nsexception_enabler.h" |
| 12 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
| 13 #import "base/mac/scoped_objc_class_swizzler.h" | |
| 13 #import "base/metrics/histogram.h" | 14 #import "base/metrics/histogram.h" |
| 14 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 15 #import "base/strings/sys_string_conversions.h" | 16 #import "base/strings/sys_string_conversions.h" |
| 16 #import "chrome/browser/app_controller_mac.h" | 17 #import "chrome/browser/app_controller_mac.h" |
| 17 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | 18 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
| 18 #include "chrome/common/crash_keys.h" | 19 #include "chrome/common/crash_keys.h" |
| 19 #import "chrome/common/mac/objc_method_swizzle.h" | |
| 20 #import "chrome/common/mac/objc_zombie.h" | 20 #import "chrome/common/mac/objc_zombie.h" |
| 21 #include "content/public/browser/browser_accessibility_state.h" | 21 #include "content/public/browser/browser_accessibility_state.h" |
| 22 #include "content/public/browser/render_view_host.h" | 22 #include "content/public/browser/render_view_host.h" |
| 23 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 // Tracking for cases being hit by -crInitWithName:reason:userInfo:. | 27 // Tracking for cases being hit by -initWithName:reason:userInfo:. |
| 28 enum ExceptionEventType { | 28 enum ExceptionEventType { |
| 29 EXCEPTION_ACCESSIBILITY = 0, | 29 EXCEPTION_ACCESSIBILITY = 0, |
| 30 EXCEPTION_MENU_ITEM_BOUNDS_CHECK, | 30 EXCEPTION_MENU_ITEM_BOUNDS_CHECK, |
| 31 EXCEPTION_VIEW_NOT_IN_WINDOW, | 31 EXCEPTION_VIEW_NOT_IN_WINDOW, |
| 32 EXCEPTION_NSURL_INIT_NIL, | 32 EXCEPTION_NSURL_INIT_NIL, |
| 33 EXCEPTION_NSDATADETECTOR_NIL_STRING, | 33 EXCEPTION_NSDATADETECTOR_NIL_STRING, |
| 34 | 34 |
| 35 // Always keep this at the end. | 35 // Always keep this at the end. |
| 36 EXCEPTION_MAX, | 36 EXCEPTION_MAX, |
| 37 }; | 37 }; |
| 38 | 38 |
| 39 void RecordExceptionEvent(ExceptionEventType event_type) { | 39 void RecordExceptionEvent(ExceptionEventType event_type) { |
| 40 UMA_HISTOGRAM_ENUMERATION("OSX.ExceptionHandlerEvents", | 40 UMA_HISTOGRAM_ENUMERATION("OSX.ExceptionHandlerEvents", |
| 41 event_type, EXCEPTION_MAX); | 41 event_type, EXCEPTION_MAX); |
| 42 } | 42 } |
| 43 | 43 |
| 44 } // namespace | 44 } // namespace |
| 45 | 45 |
| 46 // The implementation of NSExceptions break various assumptions in the | 46 // The implementation of NSExceptions break various assumptions in the |
| 47 // Chrome code. This category defines a replacement for | 47 // Chrome code. This interface defines a replacement for |
| 48 // -initWithName:reason:userInfo: for purposes of forcing a break in | 48 // -initWithName:reason:userInfo: for purposes of forcing a break in |
| 49 // the debugger when an exception is raised. -raise sounds more | 49 // the debugger when an exception is raised. -raise sounds more |
| 50 // obvious to intercept, but it doesn't catch the original throw | 50 // obvious to intercept, but it doesn't catch the original throw |
| 51 // because the objc runtime doesn't use it. | 51 // because the objc runtime doesn't use it. |
| 52 @interface NSException (CrNSExceptionSwizzle) | 52 @interface CrNSExceptionInitDonor : NSObject |
| 53 - (id)crInitWithName:(NSString*)aName | 53 - (id)initWithName:(NSString*)aName |
| 54 reason:(NSString*)aReason | 54 reason:(NSString*)aReason |
| 55 userInfo:(NSDictionary*)someUserInfo; | 55 userInfo:(NSDictionary*)someUserInfo; |
| 56 @end | 56 @end |
| 57 | 57 |
| 58 static IMP gOriginalInitIMP = NULL; | 58 static IMP gOriginalInitIMP = NULL; |
| 59 | 59 |
| 60 @implementation NSException (CrNSExceptionSwizzle) | 60 @implementation CrNSExceptionInitDonor |
| 61 - (id)crInitWithName:(NSString*)aName | 61 - (id)initWithName:(NSString*)aName |
| 62 reason:(NSString*)aReason | 62 reason:(NSString*)aReason |
| 63 userInfo:(NSDictionary*)someUserInfo { | 63 userInfo:(NSDictionary*)someUserInfo { |
| 64 // Method only called when swizzled. | 64 // Method only called when swizzled. |
| 65 DCHECK(_cmd == @selector(initWithName:reason:userInfo:)); | 65 DCHECK(gOriginalInitIMP); |
| 66 | 66 |
| 67 // Parts of Cocoa rely on creating and throwing exceptions. These are not | 67 // Parts of Cocoa rely on creating and throwing exceptions. These are not |
| 68 // worth bugging-out over. It is very important that there be zero chance that | 68 // worth bugging-out over. It is very important that there be zero chance that |
| 69 // any Chromium code is on the stack; these must be created by Apple code and | 69 // any Chromium code is on the stack; these must be created by Apple code and |
| 70 // then immediately consumed by Apple code. | 70 // then immediately consumed by Apple code. |
| 71 static NSString* const kAcceptableNSExceptionNames[] = { | 71 static NSString* const kAcceptableNSExceptionNames[] = { |
| 72 // If an object does not support an accessibility attribute, this will | 72 // If an object does not support an accessibility attribute, this will |
| 73 // get thrown. | 73 // get thrown. |
| 74 NSAccessibilityException, | 74 NSAccessibilityException, |
| 75 }; | 75 }; |
| 76 | 76 |
| 77 BOOL found = NO; | 77 BOOL found = NO; |
| 78 for (size_t i = 0; i < arraysize(kAcceptableNSExceptionNames); ++i) { | 78 for (size_t i = 0; i < arraysize(kAcceptableNSExceptionNames); ++i) { |
| 79 if (aName == kAcceptableNSExceptionNames[i]) { | 79 if (aName == kAcceptableNSExceptionNames[i]) { |
| 80 found = YES; | 80 found = YES; |
| 81 RecordExceptionEvent(EXCEPTION_ACCESSIBILITY); | 81 RecordExceptionEvent(EXCEPTION_ACCESSIBILITY); |
| 82 break; | 82 break; |
| 83 } | 83 } |
| 84 } | 84 } |
| 85 | 85 |
| 86 if (!found) { | 86 if (!found) { |
| 87 // Update breakpad with the exception info. | 87 // Update breakpad with the exception info. |
| 88 std::string value = base::StringPrintf("%s reason %s", | 88 std::string value = base::StringPrintf("%s reason %s", |
| 89 [aName UTF8String], [aReason UTF8String]); | 89 [aName UTF8String], [aReason UTF8String]); |
| 90 base::debug::SetCrashKeyValue(crash_keys::mac::kNSException, value); | 90 base::debug::SetCrashKeyValue(crash_keys::mac::kNSException, value); |
|
tapted
2014/07/25 06:59:56
note
| |
| 91 base::debug::SetCrashKeyToStackTrace(crash_keys::mac::kNSExceptionTrace, | 91 base::debug::SetCrashKeyToStackTrace(crash_keys::mac::kNSExceptionTrace, |
| 92 base::debug::StackTrace()); | 92 base::debug::StackTrace()); |
| 93 | 93 |
| 94 // Force crash for selected exceptions to generate crash dumps. | 94 // Force crash for selected exceptions to generate crash dumps. |
| 95 BOOL fatal = NO; | 95 BOOL fatal = NO; |
| 96 if (aName == NSInternalInconsistencyException) { | 96 if (aName == NSInternalInconsistencyException) { |
| 97 NSString* const kNSMenuItemArrayBoundsCheck = | 97 NSString* const kNSMenuItemArrayBoundsCheck = |
| 98 @"Invalid parameter not satisfying: (index >= 0) && " | 98 @"Invalid parameter not satisfying: (index >= 0) && " |
| 99 @"(index < [_itemArray count])"; | 99 @"(index < [_itemArray count])"; |
| 100 if ([aReason isEqualToString:kNSMenuItemArrayBoundsCheck]) { | 100 if ([aReason isEqualToString:kNSMenuItemArrayBoundsCheck]) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 } | 228 } |
| 229 | 229 |
| 230 } // namespace chrome_browser_application_mac | 230 } // namespace chrome_browser_application_mac |
| 231 | 231 |
| 232 namespace { | 232 namespace { |
| 233 | 233 |
| 234 void SwizzleInit() { | 234 void SwizzleInit() { |
| 235 // Do-nothing wrapper so that we can arrange to only swizzle | 235 // Do-nothing wrapper so that we can arrange to only swizzle |
| 236 // -[NSException raise] when DCHECK() is turned on (as opposed to | 236 // -[NSException raise] when DCHECK() is turned on (as opposed to |
| 237 // replicating the preprocess logic which turns DCHECK() on). | 237 // replicating the preprocess logic which turns DCHECK() on). |
| 238 gOriginalInitIMP = ObjcEvilDoers::SwizzleImplementedInstanceMethods( | 238 CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler, |
| 239 [NSException class], | 239 swizzle_exception, |
| 240 @selector(initWithName:reason:userInfo:), | 240 ([NSException class], |
| 241 @selector(crInitWithName:reason:userInfo:)); | 241 [CrNSExceptionInitDonor class], |
| 242 @selector(initWithName:reason:userInfo:))); | |
| 243 gOriginalInitIMP = swizzle_exception.GetOriginalImplementation(); | |
| 242 } | 244 } |
| 243 | 245 |
| 244 } // namespace | 246 } // namespace |
| 245 | 247 |
| 246 // These methods are being exposed for the purposes of overriding. | 248 // These methods are being exposed for the purposes of overriding. |
| 247 // Used to determine when a Panel window can become the key window. | 249 // Used to determine when a Panel window can become the key window. |
| 248 @interface NSApplication (PanelsCanBecomeKey) | 250 @interface NSApplication (PanelsCanBecomeKey) |
| 249 - (void)_cycleWindowsReversed:(BOOL)arg1; | 251 - (void)_cycleWindowsReversed:(BOOL)arg1; |
| 250 - (id)_removeWindow:(NSWindow*)window; | 252 - (id)_removeWindow:(NSWindow*)window; |
| 251 - (id)_setKeyWindow:(NSWindow*)window; | 253 - (id)_setKeyWindow:(NSWindow*)window; |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 605 std::vector<NSWindow*>::iterator window_iterator = | 607 std::vector<NSWindow*>::iterator window_iterator = |
| 606 std::find(previousKeyWindows_.begin(), | 608 std::find(previousKeyWindows_.begin(), |
| 607 previousKeyWindows_.end(), | 609 previousKeyWindows_.end(), |
| 608 window); | 610 window); |
| 609 if (window_iterator != previousKeyWindows_.end()) { | 611 if (window_iterator != previousKeyWindows_.end()) { |
| 610 previousKeyWindows_.erase(window_iterator); | 612 previousKeyWindows_.erase(window_iterator); |
| 611 } | 613 } |
| 612 } | 614 } |
| 613 | 615 |
| 614 @end | 616 @end |
| OLD | NEW |