Bug 964976 - Prevent crash of unsupported pixel format gralloc allocation. r=nical
[gecko.git] / xpcom / base / nsObjCExceptions.h
blobde624fdfb70d464ecfb8db202aff9a9d53af044e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // Undo the damage that exception_defines.h does.
7 #undef try
8 #undef catch
10 #ifndef nsObjCExceptions_h_
11 #define nsObjCExceptions_h_
13 #import <Foundation/Foundation.h>
15 #ifdef DEBUG
16 #import <ExceptionHandling/NSExceptionHandler.h>
17 #endif
19 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
20 #include "nsICrashReporter.h"
21 #include "nsCOMPtr.h"
22 #include "nsServiceManagerUtils.h"
23 #endif
25 #include <unistd.h>
26 #include <signal.h>
27 #include "nsError.h"
29 // Undo the damage that exception_defines.h does.
30 #undef try
31 #undef catch
33 /* NOTE: Macros that claim to abort no longer abort, see bug 486574.
34 * If you actually want to log and abort, call "nsObjCExceptionLogAbort"
35 * from an exception handler. At some point we will fix this by replacing
36 * all macros in the tree with appropriately-named macros.
39 // See Mozilla bug 163260.
40 // This file can only be included in an Objective-C context.
42 __attribute__((unused))
43 static void nsObjCExceptionLog(NSException* aException)
45 NSLog(@"Mozilla has caught an Obj-C exception [%@: %@]",
46 [aException name], [aException reason]);
48 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
49 // Attach exception info to the crash report.
50 nsCOMPtr<nsICrashReporter> crashReporter =
51 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
52 if (crashReporter)
53 crashReporter->AppendObjCExceptionInfoToAppNotes(static_cast<void*>(aException));
54 #endif
56 #ifdef DEBUG
57 @try {
58 // Try to get stack information out of the exception. 10.5 returns the stack
59 // info with the callStackReturnAddresses selector.
60 NSArray *stackTrace = nil;
61 if ([aException respondsToSelector:@selector(callStackReturnAddresses)]) {
62 NSArray* addresses = (NSArray*)
63 [aException performSelector:@selector(callStackReturnAddresses)];
64 if ([addresses count])
65 stackTrace = addresses;
68 // 10.4 doesn't respond to callStackReturnAddresses so we'll try to pull the
69 // stack info out of the userInfo. It might not be there, sadly :(
70 if (!stackTrace)
71 stackTrace = [[aException userInfo] objectForKey:NSStackTraceKey];
73 if (stackTrace) {
74 // The command line should look like this:
75 // /usr/bin/atos -p <pid> -printHeader <stack frame addresses>
76 NSMutableArray *args =
77 [NSMutableArray arrayWithCapacity:[stackTrace count] + 3];
79 [args addObject:@"-p"];
80 int pid = [[NSProcessInfo processInfo] processIdentifier];
81 [args addObject:[NSString stringWithFormat:@"%d", pid]];
83 [args addObject:@"-printHeader"];
85 unsigned int stackCount = [stackTrace count];
86 unsigned int stackIndex = 0;
87 for (; stackIndex < stackCount; stackIndex++) {
88 unsigned long address =
89 [[stackTrace objectAtIndex:stackIndex] unsignedLongValue];
90 [args addObject:[NSString stringWithFormat:@"0x%lx", address]];
93 NSPipe *outPipe = [NSPipe pipe];
95 NSTask *task = [[NSTask alloc] init];
96 [task setLaunchPath:@"/usr/bin/atos"];
97 [task setArguments:args];
98 [task setStandardOutput:outPipe];
99 [task setStandardError:outPipe];
101 NSLog(@"Generating stack trace for Obj-C exception...");
103 // This will throw an exception if the atos tool cannot be found, and in
104 // that case we'll just hit our @catch block below.
105 [task launch];
107 [task waitUntilExit];
108 [task release];
110 NSData *outData =
111 [[outPipe fileHandleForReading] readDataToEndOfFile];
112 NSString *outString =
113 [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
115 NSLog(@"Stack trace:\n%@", outString);
117 [outString release];
119 else {
120 NSLog(@"<No stack information available for Obj-C exception>");
123 @catch (NSException *exn) {
124 NSLog(@"Failed to generate stack trace for Obj-C exception [%@: %@]",
125 [exn name], [exn reason]);
127 #endif
130 __attribute__((unused))
131 static void nsObjCExceptionAbort()
133 // We need to raise a mach-o signal here, the Mozilla crash reporter on
134 // Mac OS X does not respond to POSIX signals. Raising mach-o signals directly
135 // is tricky so we do it by just derefing a null pointer.
136 int* foo = nullptr;
137 *foo = 1;
140 __attribute__((unused))
141 static void nsObjCExceptionLogAbort(NSException *e)
143 nsObjCExceptionLog(e);
144 nsObjCExceptionAbort();
147 #define NS_OBJC_TRY(_e, _fail) \
148 @try { _e; } \
149 @catch(NSException *_exn) { \
150 nsObjCExceptionLog(_exn); \
151 _fail; \
154 #define NS_OBJC_TRY_EXPR(_e, _fail) \
155 ({ \
156 typeof(_e) _tmp; \
157 @try { _tmp = (_e); } \
158 @catch(NSException *_exn) { \
159 nsObjCExceptionLog(_exn); \
160 _fail; \
162 _tmp; \
165 #define NS_OBJC_TRY_EXPR_NULL(_e) \
166 NS_OBJC_TRY_EXPR(_e, 0)
168 #define NS_OBJC_TRY_IGNORE(_e) \
169 NS_OBJC_TRY(_e, )
171 // To reduce code size the abort versions do not reuse above macros. This allows
172 // catch blocks to only contain one call.
174 #define NS_OBJC_TRY_ABORT(_e) \
175 @try { _e; } \
176 @catch(NSException *_exn) { \
177 nsObjCExceptionLog(_exn); \
180 #define NS_OBJC_TRY_EXPR_ABORT(_e) \
181 ({ \
182 typeof(_e) _tmp; \
183 @try { _tmp = (_e); } \
184 @catch(NSException *_exn) { \
185 nsObjCExceptionLog(_exn); \
187 _tmp; \
190 // For wrapping blocks of Obj-C calls. Does not actually terminate.
191 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK @try {
192 #define NS_OBJC_END_TRY_ABORT_BLOCK } @catch(NSException *_exn) { \
193 nsObjCExceptionLog(_exn); \
196 // Same as above ABORT_BLOCK but returns a value after the try/catch block to
197 // suppress compiler warnings. This allows us to avoid having to refactor code
198 // to get scoping right when wrapping an entire method.
200 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL @try {
201 #define NS_OBJC_END_TRY_ABORT_BLOCK_NIL } @catch(NSException *_exn) { \
202 nsObjCExceptionLog(_exn); \
204 return nil;
206 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL @try {
207 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL } @catch(NSException *_exn) { \
208 nsObjCExceptionLog(_exn); \
210 return nullptr;
212 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT @try {
213 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT } @catch(NSException *_exn) { \
214 nsObjCExceptionLog(_exn); \
216 return NS_ERROR_FAILURE;
218 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN @try {
219 #define NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(_rv) } @catch(NSException *_exn) { \
220 nsObjCExceptionLog(_exn);\
222 return _rv;
224 #define NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK @try {
225 #define NS_OBJC_END_TRY_LOGONLY_BLOCK } @catch(NSException *_exn) { \
226 nsObjCExceptionLog(_exn); \
229 #define NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK_RETURN @try {
230 #define NS_OBJC_END_TRY_LOGONLY_BLOCK_RETURN(_rv) } @catch(NSException *_exn) { \
231 nsObjCExceptionLog(_exn); \
233 return _rv;
235 #endif // nsObjCExceptions_h_