Bug 509130 - Crashes [@objc_msgSend | IdleTimerVector ] (OS X) caused by WebKit used by Carbon plugin (DivXBrowserPlugin). r=josh

This commit is contained in:
Steven Michaud 2009-11-09 10:10:27 -06:00
Родитель de4a7abde0
Коммит 9e51569e7c
1 изменённых файлов: 81 добавлений и 0 удалений

Просмотреть файл

@ -69,6 +69,79 @@ extern PRUint32 gLastModifierState;
// defined in nsCocoaWindow.mm
extern PRInt32 gXULModalLevel;
#ifndef __LP64__
#include <dlfcn.h>
void (*WebKit_WebInitForCarbon)() = NULL;
// Plugins may exist that use the WebKit framework. Those that are
// Carbon-based need to call WebKit's WebInitForCarbon() method. There
// currently appears to be only one Carbon WebKit plugin --
// DivXBrowserPlugin (included with the DivX Web Player,
// http://www.divx.com/en/downloads/divx/mac). See bug 509130.
//
// The source-code for WebInitForCarbon() is in the WebKit source tree's
// WebKit/mac/Carbon/CarbonUtils.mm file. Among other things it installs
// an idle timer on the main event loop, whose target is the PoolCleaner()
// function (also in CarbonUtils.mm). WebInitForCarbon() allocates an
// NSAutoreleasePool object which it stores in the global sPool variable.
// PoolCleaner() periodically releases/drains sPool and creates another
// NSAutoreleasePool object to take its place. The intention is to ensure
// an autorelease pool is in place for whatever Objective-C code may be
// called by WebKit code, and that it periodically gets "cleaned". But
// PoolCleaner()'s periodic cleaning has a very bad effect on us -- it
// causes objects to be deleted prematurely, so that attempts to access them
// cause crashes. This is probably because, when WebInitForCarbon() is
// called from a plugin in a Cocoa browser, one or more autorelease pools
// are already in place. So, other things being equal, PoolCleaner() should
// have a similar effect on any Cocoa app that hosts a Carbon WebKit plugin.
//
// PoolCleaner() only "works" if the autorelease pool count (returned by
// WKGetNSAutoreleasePoolCount(), stored in numPools) is the same as when
// sPool was last set. So we can permanently disable it by ensuring that,
// when sPool is first set, numPools gets set to a value that it will never
// have again until just after the app shell is destroyed. To accomplish
// this we need to call WebInitForCarbon() ourselves, before any plugin
// calls it (subsequent calls to WebInitForCarbon() (after the first) are
// no-ops): We release all of the app shell's autorelease pools (including
// mMainPool) just before calling WebInitForCarbon(), then restore mMainPool
// just afterwards (before the idle timer has time to call PoolCleaner()).
//
// WKGetNSAutoreleasePoolCount() only works on OS X 10.5 and below -- not on
// OS X 10.6 and above. So PoolCleaner() is always disabled on 10.6 and
// above -- we needn't do anything to explicitly disable it.
//
// WKGetNSAutoreleasePoolCount() is a thin wrapper around the following code:
//
// unsigned count = NSPushAutoreleasePool(0);
// NSPopAutoreleasePool(count);
// return count;
//
// NSPushAutoreleasePool() and NSPopAutoreleasePool() are undocumented
// functions from the Foundation framework. On OS X 10.5.X and below their
// declarations are (as best I can tell) as follows. ('capacity' is
// presumably the initial capacity, in number of items, of the autorelease
// pool to be created.)
//
// unsigned NSPushAutoreleasePool(unsigned capacity);
// void NSPopAutoreleasePool(unsigned offset);
//
// But as of OS X 10.6 these functions appear to have changed as follows:
//
// AutoreleasePool *NSPushAutoreleasePool(unsigned capacity);
// void NSPopAutoreleasePool(AutoreleasePool *aPool);
static void InitCarbonWebKit()
{
if (!WebKit_WebInitForCarbon) {
void* webkithandle = dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", RTLD_LAZY);
if (webkithandle)
*(void **)(&WebKit_WebInitForCarbon) = dlsym(webkithandle, "WebInitForCarbon");
}
if (WebKit_WebInitForCarbon)
WebKit_WebInitForCarbon();
}
#endif // __LP64__
static PRBool gAppShellMethodsSwizzled = PR_FALSE;
// List of current Cocoa app-modal windows (nested if more than one).
nsCocoaAppModalWindowList *gCocoaAppModalWindowList = NULL;
@ -363,6 +436,14 @@ nsAppShell::Init()
[localPool release];
#ifndef __LP64__
if (!nsToolkit::OnSnowLeopardOrLater()) {
[mMainPool release];
InitCarbonWebKit();
mMainPool = [[NSAutoreleasePool alloc] init];
}
#endif
return rv;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;