Title: [113138] trunk
Revision
113138
Author
[email protected]
Date
2012-04-03 22:00:54 -0700 (Tue, 03 Apr 2012)

Log Message

Crash in WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel
https://bugs.webkit.org/show_bug.cgi?id=82873

Reviewed by David Levin.

Source/WebCore:

WorkerThreadableWebSocketChannel::Bridge should properly handle the cases where inter-thread
callback is not called due to the termination of the worker run loop. Specifically, the bridge
should not send its "this" pointer to the main thread, because the bridge object may be freed
in the worker thread before the main thread starts to process.

Test: http/tests/websocket/tests/hybi/workers/worker-reload.html

* Modules/websockets/ThreadableWebSocketChannelClientWrapper.cpp:
(WebCore::ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper):
(WebCore::ThreadableWebSocketChannelClientWrapper::peer):
(WebCore::ThreadableWebSocketChannelClientWrapper::didCreateWebSocketChannel):
Renamed from setUseHixie76Protocol, as this funtion now also sets m_peer.
Sets m_syncMethodDone to true, because this function is called in the end of
synchronous wait of Bridge::initialize().
(WebCore::ThreadableWebSocketChannelClientWrapper::clearPeer):
(WebCore::ThreadableWebSocketChannelClientWrapper::useHixie76Protocol):
* Modules/websockets/ThreadableWebSocketChannelClientWrapper.h:
Add WorkerThreadableWebSocketChannel::Peer which is initialized after the creation of
WebSocketChannel in the main thread.
(ThreadableWebSocketChannelClientWrapper):
* Modules/websockets/WorkerThreadableWebSocketChannel.cpp:
(WebCore::WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel):
Don't do synchronous wait in the constructor, as a member function may be called
during the wait before the constructor finishes. The meat of the constructor has
moved to initialize() function.
(WebCore::WorkerThreadableWebSocketChannel::Bridge::Bridge):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::~Bridge):
(WorkerContextDidInitializeTask):
(WebCore::WorkerContextDidInitializeTask::create):
(WebCore::WorkerContextDidInitializeTask::~WorkerContextDidInitializeTask):
(WebCore::WorkerContextDidInitializeTask::WorkerContextDidInitializeTask):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadInitialize):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::initialize):
Don't pass "this" object to the main thread. Receive the pointer to the peer object
via ThreadableWebSocketChannelClientWrapper which is ThreadSafeRefCounted<>.
(WebCore::WorkerThreadableWebSocketChannel::Bridge::connect):
m_peer may be NULL, and we should not do anything in that case.
(WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::bufferedAmount):
(WebCore::WorkerThreadableWebSocketChannel::mainThreadClose):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::close):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::fail):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::suspend):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::resume):
* Modules/websockets/WorkerThreadableWebSocketChannel.h:
(WorkerThreadableWebSocketChannel):
(WebCore::WorkerThreadableWebSocketChannel::refThreadableWebSocketChannel):
(WebCore::WorkerThreadableWebSocketChannel::derefThreadableWebSocketChannel):
(Bridge):
* workers/DefaultSharedWorkerRepository.cpp:
(SharedWorkerProxy):
(WebCore::SharedWorkerProxy::postTaskForModeToWorkerContext):
* workers/WorkerLoaderProxy.h:
(WorkerLoaderProxy::postTaskForModeToWorkerContext):
Return bool to indicate whether postTask was successful or not. This is necessary
to avoid memory leaks of Peer object in Bridge::initialize() function.
* workers/WorkerMessagingProxy.cpp:
(WebCore::WorkerMessagingProxy::postTaskForModeToWorkerContext):
* workers/WorkerMessagingProxy.h:
(WorkerMessagingProxy):

Source/WebKit/chromium:

Change the function signature of WorkerLoaderProxy::postTaskForModeToWorkerContext().

* src/WebSharedWorkerImpl.cpp:
(WebKit::WebSharedWorkerImpl::postTaskForModeToWorkerContext):
* src/WebSharedWorkerImpl.h:
(WebSharedWorkerImpl):
* src/WebWorkerClientImpl.cpp:
(WebKit::WebWorkerClientImpl::postTaskForModeToWorkerContext):
* src/WebWorkerClientImpl.h:
(WebWorkerClientImpl):

LayoutTests:

* http/tests/websocket/tests/hybi/workers/resources/worker-reload-iframe.html: Added.
* http/tests/websocket/tests/hybi/workers/resources/worker-reload.js: Added.
* http/tests/websocket/tests/hybi/workers/worker-reload-expected.txt: Added.
* http/tests/websocket/tests/hybi/workers/worker-reload.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (113137 => 113138)


--- trunk/LayoutTests/ChangeLog	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/LayoutTests/ChangeLog	2012-04-04 05:00:54 UTC (rev 113138)
@@ -1,3 +1,15 @@
+2012-04-03  Yuta Kitamura  <[email protected]>
+
+        Crash in WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel
+        https://bugs.webkit.org/show_bug.cgi?id=82873
+
+        Reviewed by David Levin.
+
+        * http/tests/websocket/tests/hybi/workers/resources/worker-reload-iframe.html: Added.
+        * http/tests/websocket/tests/hybi/workers/resources/worker-reload.js: Added.
+        * http/tests/websocket/tests/hybi/workers/worker-reload-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/workers/worker-reload.html: Added.
+
 2012-04-03  Keishi Hattori  <[email protected]>
 
         Disable ENABLE_DATALIST for now

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload-iframe.html (0 => 113138)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload-iframe.html	2012-04-04 05:00:54 UTC (rev 113138)
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="result">Running...</div>
+<script type="text/_javascript_">
+var repeat = 0;
+var regex = new RegExp("#repeat(\\d+)");
+var match = regex.exec(location.hash);
+if (match)
+    repeat = parseInt(match[1]);
+
+if (repeat === 100) {
+    document.getElementById("result").innerHTML = "Done.";
+    parent.document.iframeFinished();
+} else {
+    new Worker("worker-reload.js");
+    location.href = "" + (repeat + 1);
+    setTimeout('location.reload()', 1);
+}
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload.js (0 => 113138)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload.js	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/worker-reload.js	2012-04-04 05:00:54 UTC (rev 113138)
@@ -0,0 +1 @@
+new WebSocket('ws://localhost:12345');

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload-expected.txt (0 => 113138)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload-expected.txt	2012-04-04 05:00:54 UTC (rev 113138)
@@ -0,0 +1,10 @@
+Reload after WebSocket creation should not cause a crash.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Inserted <iframe>.
+PASS Test finished.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload.html (0 => 113138)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/worker-reload.html	2012-04-04 05:00:54 UTC (rev 113138)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script type="text/_javascript_">
+description("Reload after WebSocket creation should not cause a crash.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+document.iframeFinished = function()
+{
+    testPassed("Test finished.");
+    finishJSTest();
+};
+
+var iframeElement = document.createElement("iframe");
+iframeElement.src = ""
+document.body.appendChild(iframeElement);
+testPassed("Inserted <iframe>.");
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (113137 => 113138)


--- trunk/Source/WebCore/ChangeLog	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/ChangeLog	2012-04-04 05:00:54 UTC (rev 113138)
@@ -1,3 +1,71 @@
+2012-04-03  Yuta Kitamura  <[email protected]>
+
+        Crash in WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel
+        https://bugs.webkit.org/show_bug.cgi?id=82873
+
+        Reviewed by David Levin.
+
+        WorkerThreadableWebSocketChannel::Bridge should properly handle the cases where inter-thread
+        callback is not called due to the termination of the worker run loop. Specifically, the bridge
+        should not send its "this" pointer to the main thread, because the bridge object may be freed
+        in the worker thread before the main thread starts to process.
+
+        Test: http/tests/websocket/tests/hybi/workers/worker-reload.html
+
+        * Modules/websockets/ThreadableWebSocketChannelClientWrapper.cpp:
+        (WebCore::ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper):
+        (WebCore::ThreadableWebSocketChannelClientWrapper::peer):
+        (WebCore::ThreadableWebSocketChannelClientWrapper::didCreateWebSocketChannel):
+        Renamed from setUseHixie76Protocol, as this funtion now also sets m_peer.
+        Sets m_syncMethodDone to true, because this function is called in the end of
+        synchronous wait of Bridge::initialize().
+        (WebCore::ThreadableWebSocketChannelClientWrapper::clearPeer):
+        (WebCore::ThreadableWebSocketChannelClientWrapper::useHixie76Protocol):
+        * Modules/websockets/ThreadableWebSocketChannelClientWrapper.h:
+        Add WorkerThreadableWebSocketChannel::Peer which is initialized after the creation of
+        WebSocketChannel in the main thread.
+        (ThreadableWebSocketChannelClientWrapper):
+        * Modules/websockets/WorkerThreadableWebSocketChannel.cpp:
+        (WebCore::WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel):
+        Don't do synchronous wait in the constructor, as a member function may be called
+        during the wait before the constructor finishes. The meat of the constructor has
+        moved to initialize() function.
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::Bridge):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::~Bridge):
+        (WorkerContextDidInitializeTask):
+        (WebCore::WorkerContextDidInitializeTask::create):
+        (WebCore::WorkerContextDidInitializeTask::~WorkerContextDidInitializeTask):
+        (WebCore::WorkerContextDidInitializeTask::WorkerContextDidInitializeTask):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadInitialize):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::initialize):
+        Don't pass "this" object to the main thread. Receive the pointer to the peer object
+        via ThreadableWebSocketChannelClientWrapper which is ThreadSafeRefCounted<>.
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::connect):
+        m_peer may be NULL, and we should not do anything in that case.
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::bufferedAmount):
+        (WebCore::WorkerThreadableWebSocketChannel::mainThreadClose):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::close):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::fail):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::suspend):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::resume):
+        * Modules/websockets/WorkerThreadableWebSocketChannel.h:
+        (WorkerThreadableWebSocketChannel):
+        (WebCore::WorkerThreadableWebSocketChannel::refThreadableWebSocketChannel):
+        (WebCore::WorkerThreadableWebSocketChannel::derefThreadableWebSocketChannel):
+        (Bridge):
+        * workers/DefaultSharedWorkerRepository.cpp:
+        (SharedWorkerProxy):
+        (WebCore::SharedWorkerProxy::postTaskForModeToWorkerContext):
+        * workers/WorkerLoaderProxy.h:
+        (WorkerLoaderProxy::postTaskForModeToWorkerContext):
+        Return bool to indicate whether postTask was successful or not. This is necessary
+        to avoid memory leaks of Peer object in Bridge::initialize() function.
+        * workers/WorkerMessagingProxy.cpp:
+        (WebCore::WorkerMessagingProxy::postTaskForModeToWorkerContext):
+        * workers/WorkerMessagingProxy.h:
+        (WorkerMessagingProxy):
+
 2012-04-03  Keishi Hattori  <[email protected]>
 
         Disable ENABLE_DATALIST for now

Modified: trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.cpp (113137 => 113138)


--- trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -44,6 +44,7 @@
 ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper(ScriptExecutionContext* context, WebSocketChannelClient* client)
     : m_context(context)
     , m_client(client)
+    , m_peer(0)
     , m_syncMethodDone(true)
     , m_useHixie76Protocol(true)
     , m_sendRequestResult(ThreadableWebSocketChannel::SendFail)
@@ -72,16 +73,28 @@
     return m_syncMethodDone;
 }
 
-bool ThreadableWebSocketChannelClientWrapper::useHixie76Protocol() const
+WorkerThreadableWebSocketChannel::Peer* ThreadableWebSocketChannelClientWrapper::peer() const
 {
-    return m_useHixie76Protocol;
+    return m_peer;
 }
 
-void ThreadableWebSocketChannelClientWrapper::setUseHixie76Protocol(bool useHixie76Protocol)
+void ThreadableWebSocketChannelClientWrapper::didCreateWebSocketChannel(WorkerThreadableWebSocketChannel::Peer* peer, bool useHixie76Protocol)
 {
+    m_peer = peer;
     m_useHixie76Protocol = useHixie76Protocol;
+    m_syncMethodDone = true;
 }
 
+void ThreadableWebSocketChannelClientWrapper::clearPeer()
+{
+    m_peer = 0;
+}
+
+bool ThreadableWebSocketChannelClientWrapper::useHixie76Protocol() const
+{
+    return m_useHixie76Protocol;
+}
+
 String ThreadableWebSocketChannelClientWrapper::subprotocol() const
 {
     if (m_subprotocol.isEmpty())

Modified: trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.h (113137 => 113138)


--- trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannelClientWrapper.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -37,6 +37,7 @@
 #include "ScriptExecutionContext.h"
 #include "ThreadableWebSocketChannel.h"
 #include "WebSocketChannelClient.h"
+#include "WorkerThreadableWebSocketChannel.h"
 #include <wtf/Forward.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/PassOwnPtr.h>
@@ -56,10 +57,13 @@
     void setSyncMethodDone();
     bool syncMethodDone() const;
 
+    WorkerThreadableWebSocketChannel::Peer* peer() const;
+    void didCreateWebSocketChannel(WorkerThreadableWebSocketChannel::Peer*, bool useHixie76Protocol);
+    void clearPeer();
+
     // The value of useHixie76Protocol flag is cachable; this value is saved after WebSocketChannel (on the main
     // thread) is constructed.
     bool useHixie76Protocol() const;
-    void setUseHixie76Protocol(bool);
 
     // Subprotocol and extensions are cached too. Will be available when didConnect() callback is invoked.
     String subprotocol() const;
@@ -100,6 +104,7 @@
 
     ScriptExecutionContext* m_context;
     WebSocketChannelClient* m_client;
+    WorkerThreadableWebSocketChannel::Peer* m_peer;
     bool m_syncMethodDone;
     bool m_useHixie76Protocol;
     // ThreadSafeRefCounted must not have String member variables.

Modified: trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp (113137 => 113138)


--- trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -57,6 +57,7 @@
     , m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(context, client))
     , m_bridge(Bridge::create(m_workerClientWrapper, m_workerContext, taskMode))
 {
+    m_bridge->initialize();
 }
 
 WorkerThreadableWebSocketChannel::~WorkerThreadableWebSocketChannel()
@@ -344,49 +345,82 @@
     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidClose, m_workerClientWrapper, unhandledBufferedAmount, closingHandshakeCompletion, code, reason), m_taskMode);
 }
 
-void WorkerThreadableWebSocketChannel::Bridge::setWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, Peer* peer, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool useHixie76Protocol)
+WorkerThreadableWebSocketChannel::Bridge::Bridge(PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassRefPtr<WorkerContext> workerContext, const String& taskMode)
+    : m_workerClientWrapper(workerClientWrapper)
+    , m_workerContext(workerContext)
+    , m_loaderProxy(m_workerContext->thread()->workerLoaderProxy())
+    , m_taskMode(taskMode)
+    , m_peer(0)
 {
-    ASSERT_UNUSED(context, context->isWorkerContext());
-    thisPtr->m_peer = peer;
-    workerClientWrapper->setUseHixie76Protocol(useHixie76Protocol);
-    workerClientWrapper->setSyncMethodDone();
+    ASSERT(m_workerClientWrapper.get());
 }
 
-void WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, PassRefPtr<ThreadableWebSocketChannelClientWrapper> prpClientWrapper, const String& taskMode)
+WorkerThreadableWebSocketChannel::Bridge::~Bridge()
 {
+    disconnect();
+}
+
+class WorkerContextDidInitializeTask : public ScriptExecutionContext::Task {
+public:
+    static PassOwnPtr<ScriptExecutionContext::Task> create(WorkerThreadableWebSocketChannel::Peer* peer,
+                                                           PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper,
+                                                           bool useHixie76Protocol)
+    {
+        return adoptPtr(new WorkerContextDidInitializeTask(peer, workerClientWrapper, useHixie76Protocol));
+    }
+
+    virtual ~WorkerContextDidInitializeTask() { }
+    virtual void performTask(ScriptExecutionContext* context) OVERRIDE
+    {
+        ASSERT_UNUSED(context, context->isWorkerContext());
+        m_workerClientWrapper->didCreateWebSocketChannel(m_peer, m_useHixie76Protocol);
+    }
+    virtual bool isCleanupTask() const OVERRIDE { return true; }
+
+private:
+    WorkerContextDidInitializeTask(WorkerThreadableWebSocketChannel::Peer* peer,
+                                   PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper,
+                                   bool useHixie76Protocol)
+        : m_peer(peer)
+        , m_workerClientWrapper(workerClientWrapper)
+        , m_useHixie76Protocol(useHixie76Protocol)
+    {
+    }
+
+    WorkerThreadableWebSocketChannel::Peer* m_peer;
+    RefPtr<ThreadableWebSocketChannelClientWrapper> m_workerClientWrapper;
+    bool m_useHixie76Protocol;
+};
+
+void WorkerThreadableWebSocketChannel::Bridge::mainThreadInitialize(ScriptExecutionContext* context, WorkerLoaderProxy* loaderProxy, PassRefPtr<ThreadableWebSocketChannelClientWrapper> prpClientWrapper, const String& taskMode)
+{
     ASSERT(isMainThread());
     ASSERT_UNUSED(context, context->isDocument());
 
     RefPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper = prpClientWrapper;
 
-    Peer* peer = Peer::create(clientWrapper, thisPtr->m_loaderProxy, context, taskMode);
-    thisPtr->m_loaderProxy.postTaskForModeToWorkerContext(
-        createCallbackTask(&Bridge::setWebSocketChannel,
-                           AllowCrossThreadAccess(thisPtr),
-                           AllowCrossThreadAccess(peer), clientWrapper, peer->useHixie76Protocol()), taskMode);
+    Peer* peer = Peer::create(clientWrapper, *loaderProxy, context, taskMode);
+    bool sent = loaderProxy->postTaskForModeToWorkerContext(
+        WorkerContextDidInitializeTask::create(peer, clientWrapper, peer->useHixie76Protocol()), taskMode);
+    if (!sent) {
+        clientWrapper->clearPeer();
+        delete peer;
+    }
 }
 
-WorkerThreadableWebSocketChannel::Bridge::Bridge(PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassRefPtr<WorkerContext> workerContext, const String& taskMode)
-    : m_workerClientWrapper(workerClientWrapper)
-    , m_workerContext(workerContext)
-    , m_loaderProxy(m_workerContext->thread()->workerLoaderProxy())
-    , m_taskMode(taskMode)
-    , m_peer(0)
+void WorkerThreadableWebSocketChannel::Bridge::initialize()
 {
-    ASSERT(m_workerClientWrapper.get());
+    ASSERT(!m_peer);
     setMethodNotCompleted();
+    RefPtr<Bridge> protect(this);
     m_loaderProxy.postTaskToLoader(
-        createCallbackTask(&Bridge::mainThreadCreateWebSocketChannel,
-                           AllowCrossThreadAccess(this), m_workerClientWrapper, m_taskMode));
+        createCallbackTask(&Bridge::mainThreadInitialize,
+                           AllowCrossThreadAccess(&m_loaderProxy), m_workerClientWrapper, m_taskMode));
     waitForMethodCompletion();
-    ASSERT(m_peer);
+    // m_peer may be null when the nested runloop exited before a peer has created.
+    m_peer = m_workerClientWrapper->peer();
 }
 
-WorkerThreadableWebSocketChannel::Bridge::~Bridge()
-{
-    disconnect();
-}
-
 void WorkerThreadableWebSocketChannel::mainThreadConnect(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& protocol)
 {
     ASSERT(isMainThread());
@@ -399,7 +433,8 @@
 void WorkerThreadableWebSocketChannel::Bridge::connect(const KURL& url, const String& protocol)
 {
     ASSERT(m_workerClientWrapper);
-    ASSERT(m_peer);
+    if (!m_peer)
+        return;
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadConnect, AllowCrossThreadAccess(m_peer), url, protocol));
 }
 
@@ -434,9 +469,8 @@
 
 ThreadableWebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
 {
-    if (!m_workerClientWrapper)
+    if (!m_workerClientWrapper || !m_peer)
         return ThreadableWebSocketChannel::SendFail;
-    ASSERT(m_peer);
     setMethodNotCompleted();
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSend, AllowCrossThreadAccess(m_peer), message));
     RefPtr<Bridge> protect(this);
@@ -449,9 +483,8 @@
 
 ThreadableWebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(const ArrayBuffer& binaryData)
 {
-    if (!m_workerClientWrapper)
+    if (!m_workerClientWrapper || !m_peer)
         return ThreadableWebSocketChannel::SendFail;
-    ASSERT(m_peer);
     // ArrayBuffer isn't thread-safe, hence the content of ArrayBuffer is copied into Vector<char>.
     OwnPtr<Vector<char> > data = "" Vector<char>(binaryData.byteLength()));
     if (binaryData.byteLength())
@@ -468,9 +501,8 @@
 
 ThreadableWebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
 {
-    if (!m_workerClientWrapper)
+    if (!m_workerClientWrapper || !m_peer)
         return ThreadableWebSocketChannel::SendFail;
-    ASSERT(m_peer);
     setMethodNotCompleted();
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendBlob, AllowCrossThreadAccess(m_peer), binaryData.url(), binaryData.type(), binaryData.size()));
     RefPtr<Bridge> protect(this);
@@ -492,9 +524,8 @@
 
 unsigned long WorkerThreadableWebSocketChannel::Bridge::bufferedAmount()
 {
-    if (!m_workerClientWrapper)
+    if (!m_workerClientWrapper || !m_peer)
         return 0;
-    ASSERT(m_peer);
     setMethodNotCompleted();
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadBufferedAmount, AllowCrossThreadAccess(m_peer)));
     RefPtr<Bridge> protect(this);
@@ -505,7 +536,7 @@
     return 0;
 }
 
-void WorkerThreadableWebSocketChannel::mainThreadClose(ScriptExecutionContext* context, Peer* peer, int code, const String&reason)
+void WorkerThreadableWebSocketChannel::mainThreadClose(ScriptExecutionContext* context, Peer* peer, int code, const String& reason)
 {
     ASSERT(isMainThread());
     ASSERT_UNUSED(context, context->isDocument());
@@ -516,7 +547,8 @@
 
 void WorkerThreadableWebSocketChannel::Bridge::close(int code, const String& reason)
 {
-    ASSERT(m_peer);
+    if (!m_peer)
+        return;
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadClose, AllowCrossThreadAccess(m_peer), code, reason));
 }
 
@@ -531,7 +563,8 @@
 
 void WorkerThreadableWebSocketChannel::Bridge::fail(const String& reason)
 {
-    ASSERT(m_peer);
+    if (!m_peer)
+        return;
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadFail, AllowCrossThreadAccess(m_peer), reason));
 }
 
@@ -566,7 +599,8 @@
 
 void WorkerThreadableWebSocketChannel::Bridge::suspend()
 {
-    ASSERT(m_peer);
+    if (!m_peer)
+        return;
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSuspend, AllowCrossThreadAccess(m_peer)));
 }
 
@@ -581,7 +615,8 @@
 
 void WorkerThreadableWebSocketChannel::Bridge::resume()
 {
-    ASSERT(m_peer);
+    if (!m_peer)
+        return;
     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadResume, AllowCrossThreadAccess(m_peer)));
 }
 

Modified: trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.h (113137 => 113138)


--- trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -36,6 +36,7 @@
 #include "PlatformString.h"
 #include "ThreadableWebSocketChannel.h"
 #include "WebSocketChannelClient.h"
+#include "WorkerContext.h"
 
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
@@ -75,14 +76,6 @@
     virtual void suspend() OVERRIDE;
     virtual void resume() OVERRIDE;
 
-    using RefCounted<WorkerThreadableWebSocketChannel>::ref;
-    using RefCounted<WorkerThreadableWebSocketChannel>::deref;
-
-protected:
-    virtual void refThreadableWebSocketChannel() { ref(); }
-    virtual void derefThreadableWebSocketChannel() { deref(); }
-
-private:
     // Generated by the bridge.  The Peer and its bridge should have identical
     // lifetimes.
     class Peer : public WebSocketChannelClient {
@@ -123,6 +116,14 @@
         String m_taskMode;
     };
 
+    using RefCounted<WorkerThreadableWebSocketChannel>::ref;
+    using RefCounted<WorkerThreadableWebSocketChannel>::deref;
+
+protected:
+    virtual void refThreadableWebSocketChannel() { ref(); }
+    virtual void derefThreadableWebSocketChannel() { deref(); }
+
+private:
     // Bridge for Peer.  Running on the worker thread.
     class Bridge : public RefCounted<Bridge> {
     public:
@@ -131,6 +132,7 @@
             return adoptRef(new Bridge(workerClientWrapper, workerContext, taskMode));
         }
         ~Bridge();
+        void initialize();
         void connect(const KURL&, const String& protocol);
         ThreadableWebSocketChannel::SendResult send(const String& message);
         ThreadableWebSocketChannel::SendResult send(const ArrayBuffer&);
@@ -151,7 +153,7 @@
         static void setWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, Peer*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, bool useHixie76Protocol);
 
         // Executed on the main thread to create a Peer for this bridge.
-        static void mainThreadCreateWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, const String& taskMode);
+        static void mainThreadInitialize(ScriptExecutionContext*, WorkerLoaderProxy*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, const String& taskMode);
 
         // Executed on the worker context's thread.
         void clearClientWrapper();

Modified: trunk/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp (113137 => 113138)


--- trunk/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/workers/DefaultSharedWorkerRepository.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -77,7 +77,7 @@
 
     // WorkerLoaderProxy
     virtual void postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task>);
-    virtual void postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String&);
+    virtual bool postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String&);
 
     // WorkerReportingProxy
     virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL);
@@ -151,12 +151,13 @@
     document->postTask(task);
 }
 
-void SharedWorkerProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
+bool SharedWorkerProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
 {
     if (isClosing())
-        return;
+        return false;
     ASSERT(m_thread);
     m_thread->runLoop().postTaskForMode(task, mode);
+    return true;
 }
 
 static void postExceptionTask(ScriptExecutionContext* context, const String& errorMessage, int lineNumber, const String& sourceURL)

Modified: trunk/Source/WebCore/workers/WorkerLoaderProxy.h (113137 => 113138)


--- trunk/Source/WebCore/workers/WorkerLoaderProxy.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/workers/WorkerLoaderProxy.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -53,7 +53,8 @@
 
         // Posts callbacks from loading code to the WorkerContext. The 'mode' is used to differentiate
         // specific synchronous loading requests so they can be 'nested', per spec.
-        virtual void postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String& mode) = 0;
+        // Returns true if the task was posted successfully.
+        virtual bool postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String& mode) = 0;
     };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/workers/WorkerMessagingProxy.cpp (113137 => 113138)


--- trunk/Source/WebCore/workers/WorkerMessagingProxy.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/workers/WorkerMessagingProxy.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -296,13 +296,14 @@
         m_queuedEarlyTasks.append(MessageWorkerContextTask::create(message, channels));
 }
 
-void WorkerMessagingProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
+bool WorkerMessagingProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
 {
     if (m_askedToTerminate)
-        return;
+        return false;
 
     ASSERT(m_workerThread);
     m_workerThread->runLoop().postTaskForMode(task, mode);
+    return true;
 }
 
 void WorkerMessagingProxy::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task)

Modified: trunk/Source/WebCore/workers/WorkerMessagingProxy.h (113137 => 113138)


--- trunk/Source/WebCore/workers/WorkerMessagingProxy.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebCore/workers/WorkerMessagingProxy.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -82,7 +82,7 @@
         // These methods are called on different threads to schedule loading
         // requests and to send callbacks back to WorkerContext.
         virtual void postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task>);
-        virtual void postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String& mode);
+        virtual bool postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task>, const String& mode);
 
         void workerThreadCreated(PassRefPtr<DedicatedWorkerThread>);
 

Modified: trunk/Source/WebKit/chromium/ChangeLog (113137 => 113138)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-04-04 05:00:54 UTC (rev 113138)
@@ -1,3 +1,21 @@
+2012-04-03  Yuta Kitamura  <[email protected]>
+
+        Crash in WebCore::WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel
+        https://bugs.webkit.org/show_bug.cgi?id=82873
+
+        Reviewed by David Levin.
+
+        Change the function signature of WorkerLoaderProxy::postTaskForModeToWorkerContext().
+
+        * src/WebSharedWorkerImpl.cpp:
+        (WebKit::WebSharedWorkerImpl::postTaskForModeToWorkerContext):
+        * src/WebSharedWorkerImpl.h:
+        (WebSharedWorkerImpl):
+        * src/WebWorkerClientImpl.cpp:
+        (WebKit::WebWorkerClientImpl::postTaskForModeToWorkerContext):
+        * src/WebWorkerClientImpl.h:
+        (WebWorkerClientImpl):
+
 2012-04-03  Ian Vollick  <[email protected]>
 
         [chromium] Include Image.h in TextFieldDecoratorImpl.cpp

Modified: trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.cpp (113137 => 113138)


--- trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -320,10 +320,11 @@
     m_loadingDocument->postTask(task);
 }
 
-void WebSharedWorkerImpl::postTaskForModeToWorkerContext(
+bool WebSharedWorkerImpl::postTaskForModeToWorkerContext(
     PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
 {
     m_workerThread->runLoop().postTaskForMode(task, mode);
+    return true;
 }
 
 

Modified: trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.h (113137 => 113138)


--- trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebKit/chromium/src/WebSharedWorkerImpl.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -86,7 +86,7 @@
 
     // WebCore::WorkerLoaderProxy methods:
     virtual void postTaskToLoader(PassOwnPtr<WebCore::ScriptExecutionContext::Task>);
-    virtual void postTaskForModeToWorkerContext(
+    virtual bool postTaskForModeToWorkerContext(
         PassOwnPtr<WebCore::ScriptExecutionContext::Task>, const WTF::String& mode);
 
     // WebFrameClient methods to support resource loading thru the 'shadow page'.

Modified: trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.cpp (113137 => 113138)


--- trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.cpp	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.cpp	2012-04-04 05:00:54 UTC (rev 113138)
@@ -149,9 +149,10 @@
     m_proxy->postTaskToLoader(task);
 }
 
-void WebWorkerClientImpl::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
+bool WebWorkerClientImpl::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
 {
     m_proxy->postTaskForModeToWorkerContext(task, mode);
+    return true;
 }
 
 void WebWorkerClientImpl::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> value, PassOwnPtr<MessagePortChannelArray> ports)

Modified: trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.h (113137 => 113138)


--- trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.h	2012-04-04 04:43:17 UTC (rev 113137)
+++ trunk/Source/WebKit/chromium/src/WebWorkerClientImpl.h	2012-04-04 05:00:54 UTC (rev 113138)
@@ -86,7 +86,7 @@
 #endif
     // WebCore::WorkerLoaderProxy methods:
     virtual void postTaskToLoader(PassOwnPtr<WebCore::ScriptExecutionContext::Task>) OVERRIDE;
-    virtual void postTaskForModeToWorkerContext(PassOwnPtr<WebCore::ScriptExecutionContext::Task>, const String& mode) OVERRIDE;
+    virtual bool postTaskForModeToWorkerContext(PassOwnPtr<WebCore::ScriptExecutionContext::Task>, const String& mode) OVERRIDE;
 
     // WebCore::WorkerObjectProxy methods:
     virtual void postMessageToWorkerObject(PassRefPtr<WebCore::SerializedScriptValue>, PassOwnPtr<WebCore::MessagePortChannelArray>) OVERRIDE;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to