Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: chrome/browser/chrome_browser_application_mac.mm

Issue 1212093002: [Mac] Redo NSException handling, and generate better stacks for C++ exceptions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include <objc/objc-exception.h>
8
7 #import "base/auto_reset.h" 9 #import "base/auto_reset.h"
8 #include "base/debug/crash_logging.h" 10 #include "base/debug/crash_logging.h"
9 #include "base/debug/stack_trace.h" 11 #include "base/debug/stack_trace.h"
10 #import "base/logging.h" 12 #import "base/logging.h"
13 #include "base/mac/call_with_eh_frame.h"
11 #import "base/mac/scoped_nsexception_enabler.h" 14 #import "base/mac/scoped_nsexception_enabler.h"
12 #import "base/mac/scoped_nsobject.h" 15 #import "base/mac/scoped_nsobject.h"
13 #import "base/mac/scoped_objc_class_swizzler.h" 16 #import "base/mac/scoped_objc_class_swizzler.h"
14 #import "base/metrics/histogram.h" 17 #import "base/metrics/histogram.h"
15 #include "base/profiler/scoped_tracker.h" 18 #include "base/profiler/scoped_tracker.h"
16 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
17 #import "base/strings/sys_string_conversions.h" 20 #import "base/strings/sys_string_conversions.h"
18 #import "chrome/browser/app_controller_mac.h" 21 #import "chrome/browser/app_controller_mac.h"
19 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 22 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
20 #include "chrome/common/crash_keys.h" 23 #include "chrome/common/crash_keys.h"
21 #import "chrome/common/mac/objc_zombie.h" 24 #import "chrome/common/mac/objc_zombie.h"
22 #include "content/public/browser/browser_accessibility_state.h" 25 #include "content/public/browser/browser_accessibility_state.h"
23 #include "content/public/browser/render_view_host.h" 26 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/web_contents.h" 27 #include "content/public/browser/web_contents.h"
25 28
26 namespace { 29 namespace chrome_browser_application_mac {
27 30
28 // Tracking for cases being hit by -crInitWithName:reason:userInfo:. 31 objc_exception_preprocessor g_next_preprocessor = nullptr;
29 enum ExceptionEventType {
30 EXCEPTION_ACCESSIBILITY = 0,
31 EXCEPTION_MENU_ITEM_BOUNDS_CHECK,
32 EXCEPTION_VIEW_NOT_IN_WINDOW,
33 EXCEPTION_NSURL_INIT_NIL,
34 EXCEPTION_NSDATADETECTOR_NIL_STRING,
35 EXCEPTION_NSREGULAREXPRESSION_NIL_STRING,
36
37 // Always keep this at the end.
38 EXCEPTION_MAX,
39 };
40
41 void RecordExceptionEvent(ExceptionEventType event_type) {
42 UMA_HISTOGRAM_ENUMERATION("OSX.ExceptionHandlerEvents",
43 event_type, EXCEPTION_MAX);
44 }
45
46 } // namespace
47
48 // The implementation of NSExceptions break various assumptions in the
49 // Chrome code. This category defines a replacement for
50 // -initWithName:reason:userInfo: for purposes of forcing a break in
51 // the debugger when an exception is raised. -raise sounds more
52 // obvious to intercept, but it doesn't catch the original throw
53 // because the objc runtime doesn't use it.
54 @interface NSException (CrNSExceptionSwizzle)
55 - (id)crInitWithName:(NSString*)aName
56 reason:(NSString*)aReason
57 userInfo:(NSDictionary*)someUserInfo;
58 @end
59
60 static IMP gOriginalInitIMP = NULL;
61
62 @implementation NSException (CrNSExceptionSwizzle)
63 - (id)crInitWithName:(NSString*)aName
64 reason:(NSString*)aReason
65 userInfo:(NSDictionary*)someUserInfo {
66 // Method only called when swizzled.
67 DCHECK(_cmd == @selector(initWithName:reason:userInfo:));
68 DCHECK(gOriginalInitIMP);
69
70 // Parts of Cocoa rely on creating and throwing exceptions. These are not
71 // worth bugging-out over. It is very important that there be zero chance that
72 // any Chromium code is on the stack; these must be created by Apple code and
73 // then immediately consumed by Apple code.
74 static NSString* const kAcceptableNSExceptionNames[] = {
75 // If an object does not support an accessibility attribute, this will
76 // get thrown.
77 NSAccessibilityException,
78 };
79
80 BOOL found = NO;
81 for (size_t i = 0; i < arraysize(kAcceptableNSExceptionNames); ++i) {
82 if (aName == kAcceptableNSExceptionNames[i]) {
83 found = YES;
84 RecordExceptionEvent(EXCEPTION_ACCESSIBILITY);
85 break;
86 }
87 }
88
89 if (!found) {
90 // Update breakpad with the exception info.
91 std::string value = base::StringPrintf("%s reason %s",
92 [aName UTF8String], [aReason UTF8String]);
93 base::debug::SetCrashKeyValue(crash_keys::mac::kNSException, value);
94 base::debug::SetCrashKeyToStackTrace(crash_keys::mac::kNSExceptionTrace,
95 base::debug::StackTrace());
96
97 // Force crash for selected exceptions to generate crash dumps.
98 BOOL fatal = NO;
99 if (aName == NSInternalInconsistencyException) {
100 NSString* const kNSMenuItemArrayBoundsCheck =
101 @"Invalid parameter not satisfying: (index >= 0) && "
102 @"(index < [_itemArray count])";
103 if ([aReason isEqualToString:kNSMenuItemArrayBoundsCheck]) {
104 RecordExceptionEvent(EXCEPTION_MENU_ITEM_BOUNDS_CHECK);
105 fatal = YES;
106 }
107
108 NSString* const kNoWindowCheck = @"View is not in any window";
109 if ([aReason isEqualToString:kNoWindowCheck]) {
110 RecordExceptionEvent(EXCEPTION_VIEW_NOT_IN_WINDOW);
111 fatal = YES;
112 }
113 }
114
115 // Mostly "unrecognized selector sent to (instance|class)". A
116 // very small number of things like inappropriate nil being passed.
117 if (aName == NSInvalidArgumentException) {
118 fatal = YES;
119
120 // TODO(shess): http://crbug.com/85463 throws this exception
121 // from ImageKit. Our code is not on the stack, so it needs to
122 // be whitelisted for now.
123 NSString* const kNSURLInitNilCheck =
124 @"*** -[NSURL initFileURLWithPath:isDirectory:]: "
125 @"nil string parameter";
126 if ([aReason isEqualToString:kNSURLInitNilCheck]) {
127 RecordExceptionEvent(EXCEPTION_NSURL_INIT_NIL);
128 fatal = NO;
129 }
130
131 // <http://crbug.com/316759> OSX 10.9 fails trying to extract
132 // structure from a string.
133 NSString* const kNSDataDetectorNilCheck =
134 @"*** -[NSDataDetector enumerateMatchesInString:"
135 @"options:range:usingBlock:]: nil argument";
136 if ([aReason isEqualToString:kNSDataDetectorNilCheck]) {
137 RecordExceptionEvent(EXCEPTION_NSDATADETECTOR_NIL_STRING);
138 fatal = NO;
139 }
140
141 // <http://crbug.com/466076> OSX 10.10 moved the method.
142 NSString* const kNSRegularExpressionNilCheck =
143 @"*** -[NSRegularExpression enumerateMatchesInString:"
144 @"options:range:usingBlock:]: nil argument";
145 if ([aReason isEqualToString:kNSRegularExpressionNilCheck]) {
146 RecordExceptionEvent(EXCEPTION_NSREGULAREXPRESSION_NIL_STRING);
147 fatal = NO;
148 }
149 }
150
151 // Dear reader: Something you just did provoked an NSException.
152 // NSException is implemented in terms of setjmp()/longjmp(),
153 // which does poor things when combined with C++ scoping
154 // (destructors are skipped). Chrome should be NSException-free,
155 // please check your backtrace and see if you can't file a bug
156 // with a repro case.
157 const bool allow = base::mac::GetNSExceptionsAllowed();
158 if (fatal && !allow) {
159 LOG(FATAL) << "Someone is trying to raise an exception! "
160 << value;
161 } else {
162 // Make sure that developers see when their code throws
163 // exceptions.
164 DCHECK(allow) << "Someone is trying to raise an exception! "
165 << value;
166 }
167 }
168
169 // Forward to the original version.
170 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo);
171 }
172 @end
173
174 namespace chrome_browser_application_mac {
175 32
176 // Maximum number of known named exceptions we'll support. There is 33 // Maximum number of known named exceptions we'll support. There is
177 // no central registration, but I only find about 75 possibilities in 34 // no central registration, but I only find about 75 possibilities in
178 // the system frameworks, and many of them are probably not 35 // the system frameworks, and many of them are probably not
179 // interesting to track in aggregate (those relating to distributed 36 // interesting to track in aggregate (those relating to distributed
180 // objects, for instance). 37 // objects, for instance).
181 const size_t kKnownNSExceptionCount = 25; 38 const size_t kKnownNSExceptionCount = 25;
182 39
183 const size_t kUnknownNSException = kKnownNSExceptionCount; 40 const size_t kUnknownNSException = kKnownNSExceptionCount;
184 41
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 } 77 }
221 } 78 }
222 return kUnknownNSException; 79 return kUnknownNSException;
223 } 80 }
224 81
225 void RecordExceptionWithUma(NSException* exception) { 82 void RecordExceptionWithUma(NSException* exception) {
226 UMA_HISTOGRAM_ENUMERATION("OSX.NSException", 83 UMA_HISTOGRAM_ENUMERATION("OSX.NSException",
227 BinForException(exception), kUnknownNSException); 84 BinForException(exception), kUnknownNSException);
228 } 85 }
229 86
87 id ExceptionPreprocessor(id exception) {
88 static bool seen_first_exception = false;
89
90 RecordExceptionWithUma(exception);
91
92 const char* const kExceptionKey =
93 seen_first_exception ? crash_keys::mac::kLastNSException
94 : crash_keys::mac::kFirstNSException;
95 NSString* value = [NSString stringWithFormat:@"%@ reason %@",
96 [exception name], [exception reason]];
97 base::debug::SetCrashKeyValue(kExceptionKey, [value UTF8String]);
98
99 const char* const kExceptionTraceKey =
100 seen_first_exception ? crash_keys::mac::kLastNSExceptionTrace
101 : crash_keys::mac::kFirstNSExceptionTrace;
102 // This exception preprocessor runs prior to the one in libobjc, which sets
103 // the -[NSException callStackReturnAddresses].
104 base::debug::SetCrashKeyToStackTrace(kExceptionTraceKey,
105 base::debug::StackTrace());
106
107 seen_first_exception = true;
108
109 // Forward to the original version.
110 if (g_next_preprocessor)
111 return g_next_preprocessor(exception);
112 return exception;
113 }
114
230 void RegisterBrowserCrApp() { 115 void RegisterBrowserCrApp() {
231 [BrowserCrApplication sharedApplication]; 116 [BrowserCrApplication sharedApplication];
232 }; 117 };
233 118
234 void Terminate() { 119 void Terminate() {
235 [NSApp terminate:nil]; 120 [NSApp terminate:nil];
236 } 121 }
237 122
238 void CancelTerminate() { 123 void CancelTerminate() {
239 [NSApp cancelTerminate:nil]; 124 [NSApp cancelTerminate:nil];
240 } 125 }
241 126
242 } // namespace chrome_browser_application_mac 127 } // namespace chrome_browser_application_mac
243 128
244 namespace {
245
246 void SwizzleInit() {
247 // Do-nothing wrapper so that we can arrange to only swizzle
248 // -[NSException raise] when DCHECK() is turned on (as opposed to
249 // replicating the preprocess logic which turns DCHECK() on).
250 CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler,
251 swizzle_exception,
252 ([NSException class],
253 @selector(initWithName:reason:userInfo:),
254 @selector(crInitWithName:reason:userInfo:)));
255 gOriginalInitIMP = swizzle_exception.GetOriginalImplementation();
256 }
257
258 } // namespace
259
260 // These methods are being exposed for the purposes of overriding. 129 // These methods are being exposed for the purposes of overriding.
261 // Used to determine when a Panel window can become the key window. 130 // Used to determine when a Panel window can become the key window.
262 @interface NSApplication (PanelsCanBecomeKey) 131 @interface NSApplication (PanelsCanBecomeKey)
263 - (void)_cycleWindowsReversed:(BOOL)arg1; 132 - (void)_cycleWindowsReversed:(BOOL)arg1;
264 - (id)_removeWindow:(NSWindow*)window; 133 - (id)_removeWindow:(NSWindow*)window;
265 - (id)_setKeyWindow:(NSWindow*)window; 134 - (id)_setKeyWindow:(NSWindow*)window;
266 @end 135 @end
267 136
268 @interface BrowserCrApplication (PrivateInternal) 137 @interface BrowserCrApplication (PrivateInternal)
269 138
270 // This must be called under the protection of previousKeyWindowsLock_. 139 // This must be called under the protection of previousKeyWindowsLock_.
271 - (void)removePreviousKeyWindow:(NSWindow*)window; 140 - (void)removePreviousKeyWindow:(NSWindow*)window;
272 141
273 @end 142 @end
274 143
275 @implementation BrowserCrApplication 144 @implementation BrowserCrApplication
276 145
277 + (void)initialize { 146 + (void)initialize {
278 // Turn all deallocated Objective-C objects into zombies, keeping 147 // Turn all deallocated Objective-C objects into zombies, keeping
279 // the most recent 10,000 of them on the treadmill. 148 // the most recent 10,000 of them on the treadmill.
280 ObjcEvilDoers::ZombieEnable(true, 10000); 149 ObjcEvilDoers::ZombieEnable(true, 10000);
150
151 chrome_browser_application_mac::g_next_preprocessor =
152 objc_setExceptionPreprocessor(
153 &chrome_browser_application_mac::ExceptionPreprocessor);
Scott Hess - ex-Googler 2015/07/06 22:34:04 Suggest checking the global before calling this, i
Robert Sesek 2015/07/07 22:26:17 Done.
281 } 154 }
282 155
283 - (id)init { 156 - (id)init {
284 SwizzleInit();
285 self = [super init]; 157 self = [super init];
286 158
287 // Sanity check to alert if overridden methods are not supported. 159 // Sanity check to alert if overridden methods are not supported.
288 DCHECK([NSApplication 160 DCHECK([NSApplication
289 instancesRespondToSelector:@selector(_cycleWindowsReversed:)]); 161 instancesRespondToSelector:@selector(_cycleWindowsReversed:)]);
290 DCHECK([NSApplication 162 DCHECK([NSApplication
291 instancesRespondToSelector:@selector(_removeWindow:)]); 163 instancesRespondToSelector:@selector(_removeWindow:)]);
292 DCHECK([NSApplication 164 DCHECK([NSApplication
293 instancesRespondToSelector:@selector(_setKeyWindow:)]); 165 instancesRespondToSelector:@selector(_setKeyWindow:)]);
294 166
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 334
463 - (BOOL)isHandlingSendEvent { 335 - (BOOL)isHandlingSendEvent {
464 return handlingSendEvent_; 336 return handlingSendEvent_;
465 } 337 }
466 338
467 - (void)setHandlingSendEvent:(BOOL)handlingSendEvent { 339 - (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
468 handlingSendEvent_ = handlingSendEvent; 340 handlingSendEvent_ = handlingSendEvent;
469 } 341 }
470 342
471 - (void)sendEvent:(NSEvent*)event { 343 - (void)sendEvent:(NSEvent*)event {
472 // tracked_objects::ScopedTracker does not support parameterized 344 base::mac::CallWithEHFrame(^{
473 // instrumentations, so a big switch with each bunch instrumented is required. 345 // tracked_objects::ScopedTracker does not support parameterized
474 switch (event.type) { 346 // instrumentations, so a big switch with each bunch instrumented is
475 case NSLeftMouseDown: 347 // required.
476 case NSLeftMouseUp: 348 switch (event.type) {
477 case NSRightMouseDown: 349 case NSLeftMouseDown:
478 case NSRightMouseUp: 350 case NSLeftMouseUp:
479 case NSMouseMoved: 351 case NSRightMouseDown:
480 case NSLeftMouseDragged: 352 case NSRightMouseUp:
481 case NSRightMouseDragged: 353 case NSMouseMoved:
482 case NSMouseEntered: 354 case NSLeftMouseDragged:
483 case NSMouseExited: 355 case NSRightMouseDragged:
484 case NSOtherMouseDown: 356 case NSMouseEntered:
485 case NSOtherMouseUp: 357 case NSMouseExited:
486 case NSOtherMouseDragged: { 358 case NSOtherMouseDown:
487 tracked_objects::ScopedTracker tracking_profile( 359 case NSOtherMouseUp:
488 FROM_HERE_WITH_EXPLICIT_FUNCTION( 360 case NSOtherMouseDragged: {
489 "463272 -[BrowserCrApplication sendEvent:] Mouse")); 361 tracked_objects::ScopedTracker tracking_profile(
490 base::mac::ScopedSendingEvent sendingEventScoper; 362 FROM_HERE_WITH_EXPLICIT_FUNCTION(
491 [super sendEvent:event]; 363 "463272 -[BrowserCrApplication sendEvent:] Mouse"));
492 break; 364 base::mac::ScopedSendingEvent sendingEventScoper;
365 [super sendEvent:event];
366 break;
367 }
368
369 case NSKeyDown:
370 case NSKeyUp: {
371 tracked_objects::ScopedTracker tracking_profile(
372 FROM_HERE_WITH_EXPLICIT_FUNCTION(
373 "463272 -[BrowserCrApplication sendEvent:] Key"));
374 base::mac::ScopedSendingEvent sendingEventScoper;
375 [super sendEvent:event];
376 break;
377 }
378
379 case NSScrollWheel: {
380 tracked_objects::ScopedTracker tracking_profile(
381 FROM_HERE_WITH_EXPLICIT_FUNCTION(
382 "463272 -[BrowserCrApplication sendEvent:] ScrollWheel"));
383 base::mac::ScopedSendingEvent sendingEventScoper;
384 [super sendEvent:event];
385 break;
386 }
387
388 case NSEventTypeGesture:
389 case NSEventTypeMagnify:
390 case NSEventTypeSwipe:
391 case NSEventTypeRotate:
392 case NSEventTypeBeginGesture:
393 case NSEventTypeEndGesture: {
394 tracked_objects::ScopedTracker tracking_profile(
395 FROM_HERE_WITH_EXPLICIT_FUNCTION(
396 "463272 -[BrowserCrApplication sendEvent:] Gesture"));
397 base::mac::ScopedSendingEvent sendingEventScoper;
398 [super sendEvent:event];
399 break;
400 }
401
402 case NSAppKitDefined: {
403 tracked_objects::ScopedTracker tracking_profile(
404 FROM_HERE_WITH_EXPLICIT_FUNCTION(
405 "463272 -[BrowserCrApplication sendEvent:] AppKit"));
406 base::mac::ScopedSendingEvent sendingEventScoper;
407 [super sendEvent:event];
408 break;
409 }
410
411 case NSSystemDefined: {
412 tracked_objects::ScopedTracker tracking_profile(
413 FROM_HERE_WITH_EXPLICIT_FUNCTION(
414 "463272 -[BrowserCrApplication sendEvent:] System"));
415 base::mac::ScopedSendingEvent sendingEventScoper;
416 [super sendEvent:event];
417 break;
418 }
419
420 default: {
421 tracked_objects::ScopedTracker tracking_profile(
422 FROM_HERE_WITH_EXPLICIT_FUNCTION(
423 "463272 -[BrowserCrApplication sendEvent:] Other"));
424 base::mac::ScopedSendingEvent sendingEventScoper;
425 [super sendEvent:event];
426 }
493 } 427 }
494 428 });
495 case NSKeyDown:
496 case NSKeyUp: {
497 tracked_objects::ScopedTracker tracking_profile(
498 FROM_HERE_WITH_EXPLICIT_FUNCTION(
499 "463272 -[BrowserCrApplication sendEvent:] Key"));
500 base::mac::ScopedSendingEvent sendingEventScoper;
501 [super sendEvent:event];
502 break;
503 }
504
505 case NSScrollWheel: {
506 tracked_objects::ScopedTracker tracking_profile(
507 FROM_HERE_WITH_EXPLICIT_FUNCTION(
508 "463272 -[BrowserCrApplication sendEvent:] ScrollWheel"));
509 base::mac::ScopedSendingEvent sendingEventScoper;
510 [super sendEvent:event];
511 break;
512 }
513
514 case NSEventTypeGesture:
515 case NSEventTypeMagnify:
516 case NSEventTypeSwipe:
517 case NSEventTypeRotate:
518 case NSEventTypeBeginGesture:
519 case NSEventTypeEndGesture: {
520 tracked_objects::ScopedTracker tracking_profile(
521 FROM_HERE_WITH_EXPLICIT_FUNCTION(
522 "463272 -[BrowserCrApplication sendEvent:] Gesture"));
523 base::mac::ScopedSendingEvent sendingEventScoper;
524 [super sendEvent:event];
525 break;
526 }
527
528 case NSAppKitDefined: {
529 tracked_objects::ScopedTracker tracking_profile(
530 FROM_HERE_WITH_EXPLICIT_FUNCTION(
531 "463272 -[BrowserCrApplication sendEvent:] AppKit"));
532 base::mac::ScopedSendingEvent sendingEventScoper;
533 [super sendEvent:event];
534 break;
535 }
536
537 case NSSystemDefined: {
538 tracked_objects::ScopedTracker tracking_profile(
539 FROM_HERE_WITH_EXPLICIT_FUNCTION(
540 "463272 -[BrowserCrApplication sendEvent:] System"));
541 base::mac::ScopedSendingEvent sendingEventScoper;
542 [super sendEvent:event];
543 break;
544 }
545
546 default: {
547 tracked_objects::ScopedTracker tracking_profile(
548 FROM_HERE_WITH_EXPLICIT_FUNCTION(
549 "463272 -[BrowserCrApplication sendEvent:] Other"));
550 base::mac::ScopedSendingEvent sendingEventScoper;
551 [super sendEvent:event];
552 }
553 }
554 }
555
556 // NSExceptions which are caught by the event loop are logged here.
557 // NSException uses setjmp/longjmp, which can be very bad for C++, so
558 // we attempt to track and report them.
559 - (void)reportException:(NSException *)anException {
560 // If we throw an exception in this code, we can create an infinite
561 // loop. If we throw out of the if() without resetting
562 // |reportException|, we'll stop reporting exceptions for this run.
563 static BOOL reportingException = NO;
564 DCHECK(!reportingException);
565 if (!reportingException) {
566 reportingException = YES;
567 chrome_browser_application_mac::RecordExceptionWithUma(anException);
568
569 // http://crbug.com/45928 is a bug about needing to double-close
570 // windows sometimes. One theory is that |-isHandlingSendEvent|
571 // gets latched to always return |YES|. Since scopers are used to
572 // manipulate that value, that should not be possible. One way to
573 // sidestep scopers is setjmp/longjmp (see above). The following
574 // is to "fix" this while the more fundamental concern is
575 // addressed elsewhere.
576 [self setHandlingSendEvent:NO];
577
578 // If |ScopedNSExceptionEnabler| is used to allow exceptions, and an
579 // uncaught exception is thrown, it will throw past all of the scopers.
580 // Reset the flag so that future exceptions are not masked.
581 base::mac::SetNSExceptionsAllowed(false);
582
583 // Store some human-readable information in breakpad keys in case
584 // there is a crash. Since breakpad does not provide infinite
585 // storage, we track two exceptions. The first exception thrown
586 // is tracked because it may be the one which caused the system to
587 // go off the rails. The last exception thrown is tracked because
588 // it may be the one most directly associated with the crash.
589 static BOOL trackedFirstException = NO;
590
591 const char* const kExceptionKey =
592 trackedFirstException ? crash_keys::mac::kLastNSException
593 : crash_keys::mac::kFirstNSException;
594 NSString* value = [NSString stringWithFormat:@"%@ reason %@",
595 [anException name], [anException reason]];
596 base::debug::SetCrashKeyValue(kExceptionKey, [value UTF8String]);
597
598 // Encode the callstack from point of throw.
599 // TODO(shess): Our swizzle plus the 23-frame limit plus Cocoa
600 // overhead may make this less than useful. If so, perhaps skip
601 // some items and/or use two keys.
602 const char* const kExceptionBtKey =
603 trackedFirstException ? crash_keys::mac::kLastNSExceptionTrace
604 : crash_keys::mac::kFirstNSExceptionTrace;
605 NSArray* addressArray = [anException callStackReturnAddresses];
606 NSUInteger addressCount = [addressArray count];
607 if (addressCount) {
608 // SetCrashKeyFromAddresses() only encodes 23, so that's a natural limit.
609 const NSUInteger kAddressCountMax = 23;
610 void* addresses[kAddressCountMax];
611 if (addressCount > kAddressCountMax)
612 addressCount = kAddressCountMax;
613
614 for (NSUInteger i = 0; i < addressCount; ++i) {
615 addresses[i] = reinterpret_cast<void*>(
616 [[addressArray objectAtIndex:i] unsignedIntegerValue]);
617 }
618 base::debug::SetCrashKeyFromAddresses(
619 kExceptionBtKey, addresses, static_cast<size_t>(addressCount));
620 } else {
621 base::debug::ClearCrashKey(kExceptionBtKey);
622 }
623 trackedFirstException = YES;
624
625 reportingException = NO;
626 }
627
628 [super reportException:anException];
629 } 429 }
630 430
631 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 431 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
632 // This is an undocument attribute that's set when VoiceOver is turned on/off. 432 // This is an undocument attribute that's set when VoiceOver is turned on/off.
633 if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) { 433 if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
634 content::BrowserAccessibilityState* accessibility_state = 434 content::BrowserAccessibilityState* accessibility_state =
635 content::BrowserAccessibilityState::GetInstance(); 435 content::BrowserAccessibilityState::GetInstance();
636 if ([value intValue] == 1) 436 if ([value intValue] == 1)
637 accessibility_state->OnScreenReaderDetected(); 437 accessibility_state->OnScreenReaderDetected();
638 else 438 else
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 std::vector<NSWindow*>::iterator window_iterator = 485 std::vector<NSWindow*>::iterator window_iterator =
686 std::find(previousKeyWindows_.begin(), 486 std::find(previousKeyWindows_.begin(),
687 previousKeyWindows_.end(), 487 previousKeyWindows_.end(),
688 window); 488 window);
689 if (window_iterator != previousKeyWindows_.end()) { 489 if (window_iterator != previousKeyWindows_.end()) {
690 previousKeyWindows_.erase(window_iterator); 490 previousKeyWindows_.erase(window_iterator);
691 } 491 }
692 } 492 }
693 493
694 @end 494 @end
OLDNEW
« base/mac/call_with_eh_frame_unittest.mm ('K') | « base/message_loop/message_pump_mac.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698