Obj-C Exceptions In Gecko

From MozillaWiki
Jump to: navigation, search

See bug 163260.

Protecting Ourselves

This page is written for the people doing the original wrapping implementation for now.

The basic problem we have is that almost every call into any of Apple's frameworks (C, C++, or Obj-C) could potentially throw an Obj-C exception and unwind our stack with nasty consequences. Sometimes the browser crashes, sometimes it just appears to have lost its mind, and theoretically there could be security consequences. This is because we have no handlers in place now and as the stack unwinds code gets skipped and C++ temporary objects do not get their destructors run.

You can read more about it in the bug, but the conclusion we came to is that we need to wrap all calls into Apple frameworks with Obj-C exception handlers. This means Carbon, Cocoa, Quicktime, printing, etc. The only known exceptions are standard C and C++ library functions, Unix/Posix functions, and low-level Mach calls.

I have checked in a set of macros for doing that, see this file:

mozilla/xpcom/base/nsObjCExceptions.h

Before you start doing anything, please read through every line of that file and make sure you understand what all of it is for. If you don't understand anything please ask me on email or irc. It wouldn't be very awesome if you posted a bunch of work and had to do it all over again.

Another thing to read over is nsAppShell.mm. I have done the work for nsAppShell.mm already and checked it in. Make sure you understand why I made the choices I did there, and again ask if you are unclear about anything.

When wrapping calls in a method, the first choice you'll have to make is whether to wrap specific calls or the whole method impl. Which one you pick is usually a matter of cleanliness. If there is a big method with a single Apple framework call in it, you might just want to wrap that specific call. Your choice of macros are these:

  • For wrapping calls that are not expressions, do not return values (at least not ones we care about)
      • NS_OBJC_TRY_IGNORE();
      • NS_OBJC_TRY_ABORT();
  • For wrapping expressions that return a value
      • NS_OBJC_TRY_EXPR_NULL();
      • NS_OBJC_TRY_EXPR_ABORT();

An example of non-EXPR macro usage:

NS_OBJC_TRY_ABORT([bar doSomething]);

An example of EXPR macro usage:

foo = NS_OBJC_TRY_EXPR_ABORT([bar doSomething]);

The macros that include ABORT will kill the app if they catch an exception, you will almost always want to use these. It saves a lot of time if we don't have to think about recovery strategies for calls. In order to code for recovery you'd have to understand something about the context of the code you are working in. If we start seeing exceptions killing the app it'll be easy to go back and code the calls that are throwing for recovery. That probably won't happen and if it does it'll probably be just 1-2 calls we need to not abort on.

There are currently three options for wrapping blocks of code.

  • Basic wrapping, use anywhere
      • NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
      • NS_OBJC_END_TRY_ABORT_BLOCK;
  • Use to wrap an entire method that returns an Obj-C pointer
      • NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
      • NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
  • Used to wrap an entire method that returns an xpcom result code (nsresult)
      • NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
      • NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  • Used to wrap an entire method, returns the argument given to the END macro
      • NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
      • NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(_rv);

We will probably add another block type that returns nsnull, for use with methods that return xpcom objects, we might add others as the need arises. For any other place where you would like to wrap an entire method, you'll have to use the first basic block macros and refactor code to correctly to place the return statement after the end macro. This means you'll also have to scope any variables used in the return statement correctly.

When you put a block macro into a method, it should contain a completely empty newline before and after it. The exceptions are when you are wrapping an entire method, there should be a completely empty newline after the start macro and before the end macro.

The header file that contains these macros can only be used in an Obj-C context, for the most part this means files with the ".mm" extension. Mac-only files that contain Apple framework calls and do not end in ".mm" should be renamed to ".mm". We will devise a strategy for dealing with cross-platform files that contain Apple framework calls later.

-Josh Aas

Note that -fobjc-extensions needs to be passed to the compiler. This is already being done for widget/src/cocoa.

-Stan

Work Areas

These are all of the files in the tree that gets pulled for Firefox that have extensions of ".m" or ".mm". We'll start with these. When a file has been completed and checked in we'll strike it. After these files are complete we'll go after files that need to be renamed to ".mm" and files that have to use a different extension.

  • toolkit bug 417566
      • /toolkit/xre/nsNativeAppSupportCocoa.mm
      • /toolkit/xre/MacApplicationDelegate.mm
      • /toolkit/crashreporter/mac_utils.mm
      • /toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
      • /toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm
      • /toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm
      • /toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.m
      • /toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m
      • /toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m
      • /toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m
      • /toolkit/crashreporter/client/crashreporter_osx.mm not needed
      • /toolkit/mozapps/update/src/updater/progressui_osx.mm not needed
      • /toolkit/mozapps/update/src/updater/launchchild_osx.mm not needed
      • /toolkit/components/alerts/src/mac/mozGrowlDelegate.mm
      • /toolkit/components/alerts/src/mac/nsAlertsImageLoadListener.mm
      • /toolkit/components/alerts/src/mac/nsAlertsService.mm
      • /toolkit/components/alerts/src/mac/nsNotificationsList.mm
      • /toolkit/components/alerts/src/mac/growl/NSURLAdditions.m
      • /toolkit/components/alerts/src/mac/growl/GrowlApplicationBridge.m
      • /toolkit/components/alerts/src/mac/growl/GrowlPathUtil.m
      • /toolkit/xre/MacLaunchHelper.m
  • widget bug 417558
      • /widget/src/cocoa/nsDeviceContextSpecX.mm
      • /widget/src/cocoa/nsIdleServiceX.mm
      • /widget/src/cocoa/nsCocoaWindow.mm
      • /widget/src/cocoa/nsMenuX.mm
      • /widget/src/cocoa/nsPrintOptionsX.mm
      • /widget/src/cocoa/nsToolkit.mm
      • /widget/src/cocoa/nsPrintSessionX.mm
      • /widget/src/cocoa/nsNativeThemeCocoa.mm
      • /widget/src/cocoa/nsPrintSettingsX.mm
      • /widget/src/cocoa/nsMenuItemIconX.mm
      • /widget/src/cocoa/nsFilePicker.mm
      • /widget/src/cocoa/nsScreenManagerCocoa.mm
      • /widget/src/cocoa/nsMacCursor.mm
      • /widget/src/cocoa/nsBidiKeyboard.mm
      • /widget/src/cocoa/nsMenuItemX.mm
      • /widget/src/cocoa/nsAppShell.mm
      • /widget/src/cocoa/nsClipboard.mm
      • /widget/src/cocoa/nsScreenCocoa.mm
      • /widget/src/cocoa/nsDragService.mm
      • /widget/src/cocoa/nsCursorManager.mm
      • /widget/src/cocoa/nsChildView.mm
      • /widget/src/cocoa/nsCocoaUtils.mm
      • /widget/src/cocoa/nsWindowMap.mm
      • /widget/src/cocoa/nsMenuBarX.h
      • /widget/src/cocoa/nsMenuBarX.mm
      • /widget/src/cocoa/nsWidgetFactory.mm
      • /widget/src/cocoa/nsLookAndFeel.mm
      • /widget/src/cocoa/nsSound.mm
  • extensions bug 417563
      • /extensions/spellcheck/osxspell/src/mozOSXSpell.mm
      • /extensions/java/xpcom/src/MacJawt.mm not needed
  • accessible bug 417564
      • /accessible/src/mac/mozDocAccessible.mm
      • /accessible/src/mac/nsAccessNodeWrap.mm
      • /accessible/src/mac/mozActionElements.mm
      • /accessible/src/mac/nsAccessibleWrap.mm
      • /accessible/src/mac/mozAccessible.mm
      • /accessible/src/mac/mozTextAccessible.mm
      • /accessible/src/mac/nsRootAccessibleWrap.mm
  • gfx bug 417560
      • /gfx/src/mac/nsCocoaImageUtils.mm not used
      • /gfx/thebes/test/gfxTestCocoaHelper.mm test file only
      • /gfx/thebes/src/gfxQuartzFontCache.mm
  • modules bug 417562
      • /modules/libpr0n/decoders/icon/mac/nsIconChannelCocoa.mm
    测试一下 呵呵呵