Changeset 15750 in webkit


Ignore:
Timestamp:
Aug 1, 2006 4:06:00 PM (18 years ago)
Author:
tomernic
Message:

Reviewed by John Sullivan.

<rdar://problem/4480737> Flash crashes after it replaces itself via a document.write()


I kind of hate to do this, but this is the best way to work around buggy plug-ins like Flash that assume that
NPP_Destroy() cannot be called while the browser is calling one of its other plug-in functions. The classic
situation is a plug-in that replaces itself via an NPN_Invoke() that executes a document.write().

  • Plugins/WebBaseNetscapePluginView.h:
  • Plugins/WebBaseNetscapePluginView.m: (-[WebBaseNetscapePluginView sendEvent:]): Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions. (-[WebBaseNetscapePluginView setWindowIfNecessary]): ditto (-[WebBaseNetscapePluginView start]): It should not be possible to start a plug-in instance while we are calling into it (one of those chicken/egg problems). Added a sanity-checking assertion. (-[WebBaseNetscapePluginView stop]): If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said plugin-function returns. (-[WebBaseNetscapePluginView pluginScriptableObject]): Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions. (-[WebBaseNetscapePluginView willCallPlugInFunction]): Increment plug-in function call depth. (-[WebBaseNetscapePluginView didCallPlugInFunction]): Decrement plug-in function call depth. Stop if we're supposed to stop. (-[WebBaseNetscapePluginView evaluateJavaScriptPluginRequest:]): Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions. (-[WebBaseNetscapePluginView webFrame:didFinishLoadWithReason:]): ditto (-[WebBaseNetscapePluginView _printedPluginBitmap]): ditto
  • Plugins/WebBaseNetscapePluginStream.m: (-[WebBaseNetscapePluginStream startStreamResponseURL:expectedContentLength:lastModifiedDate:MIMEType:]): Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions. (-[WebBaseNetscapePluginStream _destroyStream]): ditto (-[WebBaseNetscapePluginStream _deliverData]): ditto
Location:
trunk/WebKit
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKit/ChangeLog

    r15747 r15750  
     12006-08-01  Tim Omernick  <timo@apple.com>
     2
     3        Reviewed by John Sullivan.
     4
     5        <rdar://problem/4480737> Flash crashes after it replaces itself via a document.write()
     6       
     7        I kind of hate to do this, but this is the best way to work around buggy plug-ins like Flash that assume that
     8        NPP_Destroy() cannot be called while the browser is calling one of its other plug-in functions.  The classic
     9        situation is a plug-in that replaces itself via an NPN_Invoke() that executes a document.write().
     10
     11        * Plugins/WebBaseNetscapePluginView.h:
     12        * Plugins/WebBaseNetscapePluginView.m:
     13        (-[WebBaseNetscapePluginView sendEvent:]):
     14        Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions.
     15        (-[WebBaseNetscapePluginView setWindowIfNecessary]):
     16        ditto
     17        (-[WebBaseNetscapePluginView start]):
     18        It should not be possible to start a plug-in instance while we are calling into it (one of those chicken/egg
     19        problems).  Added a sanity-checking assertion.
     20        (-[WebBaseNetscapePluginView stop]):
     21        If we're already calling a plug-in function, do not call NPP_Destroy().  The plug-in function we are calling
     22        may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
     23        plugin-function returns.
     24        (-[WebBaseNetscapePluginView pluginScriptableObject]):
     25        Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions.
     26        (-[WebBaseNetscapePluginView willCallPlugInFunction]):
     27        Increment plug-in function call depth.
     28        (-[WebBaseNetscapePluginView didCallPlugInFunction]):
     29        Decrement plug-in function call depth.  Stop if we're supposed to stop.
     30        (-[WebBaseNetscapePluginView evaluateJavaScriptPluginRequest:]):
     31        Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions.
     32        (-[WebBaseNetscapePluginView webFrame:didFinishLoadWithReason:]):
     33        ditto
     34        (-[WebBaseNetscapePluginView _printedPluginBitmap]):
     35        ditto
     36
     37        * Plugins/WebBaseNetscapePluginStream.m:
     38        (-[WebBaseNetscapePluginStream startStreamResponseURL:expectedContentLength:lastModifiedDate:MIMEType:]):
     39        Call -willCallPlugInFunction and -didCallPlugInFunction around calls to the NPP_* functions.
     40        (-[WebBaseNetscapePluginStream _destroyStream]):
     41        ditto
     42        (-[WebBaseNetscapePluginStream _deliverData]):
     43        ditto
     44
    1452006-08-01  Maciej Stachowiak  <mjs@apple.com>
    246
  • trunk/WebKit/Plugins/WebBaseNetscapePluginStream.m

    r14811 r15750  
    222222    // FIXME: Need a way to check if stream is seekable
    223223
     224    [pluginView willCallPlugInFunction];
    224225    NPError npErr = NPP_NewStream(instance, (char *)[MIMEType UTF8String], &stream, NO, &transferMode);
     226    [pluginView didCallPlugInFunction];
    225227    LOG(Plugins, "NPP_NewStream URL=%@ MIME=%@ error=%d", responseURL, MIMEType, npErr);
    226228
     
    273275            char *carbonPath = CarbonPathFromPOSIXPath(path);
    274276            ASSERT(carbonPath != NULL);
     277            [pluginView willCallPlugInFunction];
    275278            NPP_StreamAsFile(instance, &stream, carbonPath);
     279            [pluginView didCallPlugInFunction];
    276280
    277281            // Delete the file after calling NPP_StreamAsFile(), instead of in -dealloc/-finalize.  It should be OK
     
    287291       
    288292        NPError npErr;
     293        [pluginView willCallPlugInFunction];
    289294        npErr = NPP_DestroyStream(instance, &stream, reason);
     295        [pluginView didCallPlugInFunction];
    290296        LOG(Plugins, "NPP_DestroyStream responseURL=%@ error=%d", responseURL, npErr);
    291297       
     
    295301    if (sendNotification) {
    296302        // NPP_URLNotify expects the request URL, not the response URL.
     303        [pluginView willCallPlugInFunction];
    297304        NPP_URLNotify(instance, [requestURL _web_URLCString], reason, notifyData);
     305        [pluginView didCallPlugInFunction];
    298306        LOG(Plugins, "NPP_URLNotify requestURL=%@ reason=%d", requestURL, reason);
    299307    }
     
    384392   
    385393    while (totalBytesDelivered < totalBytes) {
     394        [pluginView willCallPlugInFunction];
    386395        int32 deliveryBytes = NPP_WriteReady(instance, &stream);
     396        [pluginView didCallPlugInFunction];
    387397        LOG(Plugins, "NPP_WriteReady responseURL=%@ bytes=%d", responseURL, deliveryBytes);
    388398       
     
    394404            deliveryBytes = MIN(deliveryBytes, totalBytes - totalBytesDelivered);
    395405            NSData *subdata = [deliveryData subdataWithRange:NSMakeRange(totalBytesDelivered, deliveryBytes)];
     406            [pluginView willCallPlugInFunction];
    396407            deliveryBytes = NPP_Write(instance, &stream, offset, [subdata length], (void *)[subdata bytes]);
     408            [pluginView didCallPlugInFunction];
    397409            if (deliveryBytes < 0) {
    398410                // Netscape documentation says that a negative result from NPP_Write means cancel the load.
  • trunk/WebKit/Plugins/WebBaseNetscapePluginView.h

    r15407 r15750  
    7777    BOOL isTransparent;
    7878    BOOL isCompletelyObscured;
     79    BOOL shouldStopSoon;
     80    unsigned pluginFunctionCallDepth;
    7981   
    8082    DOMElement *element;
     
    130132- (void)viewDidMoveToHostWindow;
    131133
    132 /* Returns the NPObject that represents the plugin interface. */
     134// Returns the NPObject that represents the plugin interface.
    133135- (void *)pluginScriptableObject;
    134136
     137// -willCallPlugInFunction must be called before calling any of the NPP_* functions for this view's NPP instance.
     138// This is necessary to ensure that plug-ins are not destroyed while WebKit calls into them.  Some plug-ins (Flash
     139// at least) are written with the assumption that nothing they do in their plug-in functions can cause NPP_Destroy()
     140// to be called.  Unfortunately, this is not true, especially if the plug-in uses NPN_Invoke() to execute a
     141// document.write(), which clears the document and destroys the plug-in.
     142// See <rdar://problem/4480737>.
     143- (void)willCallPlugInFunction;
     144
     145// -didCallPlugInFunction should be called after returning from a plug-in function.  It should be called exactly
     146// once for every call to -willCallPlugInFunction.
     147// See <rdar://problem/4480737>.
     148- (void)didCallPlugInFunction;
     149
    135150@end
  • trunk/WebKit/Plugins/WebBaseNetscapePluginView.m

    r15698 r15750  
    611611    [[self retain] autorelease];
    612612   
     613    [self willCallPlugInFunction];
    613614    BOOL acceptedEvent = NPP_HandleEvent(instance, event);
     615    [self didCallPlugInFunction];
    614616   
    615617    currentEventIsUserGesture = NO;
     
    10701072        ASSERT((drawingModel != NPDrawingModelCoreGraphics && drawingModel != NPDrawingModelOpenGL) || [NSView focusView] == self);
    10711073       
     1074        [self willCallPlugInFunction];
    10721075        npErr = NPP_SetWindow(instance, &window);
     1076        [self didCallPlugInFunction];
    10731077        inSetWindow = NO;
    10741078
     
    12081212    window.type = NPWindowTypeWindow;
    12091213   
     1214    // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
     1215    ASSERT(pluginFunctionCallDepth == 0);
     1216
    12101217    [[self class] setCurrentPluginView:self];
    12111218    NPError npErr = NPP_New((char *)[MIMEType cString], instance, mode, argsCount, cAttributes, cValues, NULL);
     
    12541261- (void)stop
    12551262{
     1263    // If we're already calling a plug-in function, do not call NPP_Destroy().  The plug-in function we are calling
     1264    // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
     1265    // plugin-function returns.
     1266    // See <rdar://problem/4480737>.
     1267    if (pluginFunctionCallDepth > 0) {
     1268        shouldStopSoon = YES;
     1269        return;
     1270    }
     1271   
    12561272    [self removeTrackingRect];
    12571273
     
    16951711    if (NPP_GetValue) {
    16961712        void *value = 0;
     1713        [self willCallPlugInFunction];
    16971714        NPError npErr = NPP_GetValue (instance, NPPVpluginScriptableNPObject, (void *)&value);
     1715        [self didCallPlugInFunction];
    16981716        if (npErr == NPERR_NO_ERROR) {
    16991717            return value;
     
    17031721}
    17041722
     1723- (void)willCallPlugInFunction
     1724{
     1725    // Could try to prevent infinite recursion here, but it's probably not worth the effort.
     1726    pluginFunctionCallDepth++;
     1727}
     1728
     1729- (void)didCallPlugInFunction
     1730{
     1731    ASSERT(pluginFunctionCallDepth > 0);
     1732    pluginFunctionCallDepth--;
     1733   
     1734    // If -stop was called while we were calling into a plug-in function, and we're no longer
     1735    // inside a plug-in function, stop now.
     1736    if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
     1737        shouldStopSoon = NO;
     1738        [self stop];
     1739    }
     1740}
    17051741
    17061742@end
     
    17511787        // like we do in KHTMLPartBrowserExtension::openURLRequest.
    17521788        if ([JSPluginRequest sendNotification]) {
     1789            [self willCallPlugInFunction];
    17531790            NPP_URLNotify(instance, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
     1791            [self didCallPlugInFunction];
    17541792        }
    17551793    } else if ([result length] > 0) {
     
    17781816    ASSERT([pluginRequest sendNotification]);
    17791817       
     1818    [self willCallPlugInFunction];
    17801819    NPP_URLNotify(instance, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
     1820    [self didCallPlugInFunction];
    17811821   
    17821822    [pendingFrameLoads removeObjectForKey:webFrame];
     
    23702410   
    23712411    // Tell the plugin to print into the GWorld
     2412    [self willCallPlugInFunction];
    23722413    NPP_Print(instance, &npPrint);
     2414    [self didCallPlugInFunction];
    23732415
    23742416    // Don't need the GWorld anymore
Note: See TracChangeset for help on using the changeset viewer.