RESOLVED FIXED 183053
MessagePort is not always destroyed in the right thread
https://bugs.webkit.org/show_bug.cgi?id=183053
Summary MessagePort is not always destroyed in the right thread
youenn fablet
Reported 2018-02-22 12:20:37 PST
Ran into the following crash when running WPT service worker tests: ASSERTION FAILED: (is<Document>(*this) && isMainThread()) || (is<WorkerGlobalScope>(*this) && downcast<WorkerGlobalScope>(*this).thread().thread() == &Thread::current()) ./dom/ScriptExecutionContext.cpp(174) : void WebCore::ScriptExecutionContext::destroyedMessagePort(WebCore::MessagePort &) 1 0x395bf54ad WTFCrash 2 0x3870f9304 WebCore::ScriptExecutionContext::destroyedMessagePort(WebCore::MessagePort&) 3 0x3870770ad WebCore::MessagePort::~MessagePort() 4 0x387077145 WebCore::MessagePort::~MessagePort() 5 0x387077189 WebCore::MessagePort::~MessagePort() 6 0x3870769f2 WebCore::MessagePort::deref() const 7 0x380a0dd6e void WTF::derefIfNotNull<WebCore::MessagePort>(WebCore::MessagePort*) 8 0x380a0dd39 WTF::RefPtr<WebCore::MessagePort, WTF::DumbPtrTraits<WebCore::MessagePort> >::~RefPtr() 9 0x380a06395 WTF::RefPtr<WebCore::MessagePort, WTF::DumbPtrTraits<WebCore::MessagePort> >::~RefPtr() 10 0x380a05d3f WebKit::WebMessagePortChannelProvider::checkProcessLocalPortForActivity(WebCore::MessagePortIdentifier const&, unsigned long long) 11 0x380c9cea9 WebKit::WebProcess::checkProcessLocalPortForActivity(WebCore::MessagePortIdentifier const&, unsigned long long) 12 0x380cf6890 void IPC::callMemberFunctionImpl<WebKit::WebProcess, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long), std::__1::tuple<WebCore::MessagePortIdentifier, unsigned long long>, 0ul, 1ul>(WebKit::WebProcess*, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long), std::__1::tuple<WebCore::MessagePortIdentifier, unsigned long long>&&, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) 13 0x380cf65b0 void IPC::callMemberFunction<WebKit::WebProcess, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long), std::__1::tuple<WebCore::MessagePortIdentifier, unsigned long long>, std::__1::integer_sequence<unsigned long, 0ul, 1ul> >(std::__1::tuple<WebCore::MessagePortIdentifier, unsigned long long>&&, WebKit::WebProcess*, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long)) 14 0x380ceb9b5 void IPC::handleMessage<Messages::WebProcess::CheckProcessLocalPortForActivity, WebKit::WebProcess, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long)>(IPC::Decoder&, WebKit::WebProcess*, void (WebKit::WebProcess::*)(WebCore::MessagePortIdentifier const&, unsigned long long)) 15 0x380ce6c36 WebKit::WebProcess::didReceiveWebProcessMessage(IPC::Connection&, IPC::Decoder&) 16 0x380c9757b WebKit::WebProcess::didReceiveMessage(IPC::Connection&, IPC::Decoder&) 17 0x3801468b3 IPC::Connection::dispatchMessage(IPC::Decoder&) 18 0x38013be98 IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >) 19 0x380146eba IPC::Connection::dispatchOneMessage() 20 0x38015f37d IPC::Connection::enqueueIncomingMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >)::$_14::operator()() 21 0x38015f2d9 WTF::Function<void ()>::CallableWrapper<IPC::Connection::enqueueIncomingMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >)::$_14>::call() 22 0x395c115cb WTF::Function<void ()>::operator()() const 23 0x395c56473 WTF::RunLoop::performWork() 24 0x395c56d14 WTF::RunLoop::performWork(void*) 25 0x7fff36d102d1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 26 0x7fff36dc9c9c __CFRunLoopDoSource0 27 0x7fff36cf2e60 __CFRunLoopDoSources0 28 0x7fff36cf22dd __CFRunLoopRun 29 0x7fff36cf1b43 CFRunLoopRunSpecific 30 0x7fff35fe2f16 RunCurrentEventLoopInMode 31 0x7fff35fe2c86 ReceiveNextEventCommon
Attachments
Patch (7.90 KB, patch)
2018-02-22 12:27 PST, youenn fablet
no flags
Patch (8.78 KB, patch)
2018-02-25 16:08 PST, youenn fablet
no flags
youenn fablet
Comment 1 2018-02-22 12:22:23 PST
Looking at MessagePort::existingMessagePortForIdentifier implementation, it returns a RefPtr<MessagePort>. Since it can be called from any thread, we could for instance retain the lock until the MessagePort is used.
youenn fablet
Comment 2 2018-02-22 12:27:58 PST
Chris Dumez
Comment 3 2018-02-22 12:34:03 PST
Comment on attachment 334467 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=334467&action=review > Source/WebCore/ChangeLog:3 > + MessagePort is not always destroyed in the right thread Shouldn't we fix this? The patch does not seem address this particular issue. It seems bad that a MessagePort would be used on one thread but could be destroyed on another thread while being used. Brady is more familiar with this code however. > Source/WebCore/dom/MessagePort.cpp:80 > + callback(allMessagePorts().get(identifier)); This could in theory cause deadlocks if the callback calls existingMessagePortForIdentifier().
youenn fablet
Comment 4 2018-02-22 12:45:11 PST
(In reply to Chris Dumez from comment #3) > Comment on attachment 334467 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=334467&action=review > > > Source/WebCore/ChangeLog:3 > > + MessagePort is not always destroyed in the right thread > > Shouldn't we fix this? The patch does not seem address this particular issue. As I read the code, as long as we hold the lock, no MessagePort can be destroyed. Since existingMessagePortForIdentifier() is not refing anymore a MessagePort, it cannot cause it to be destroyed in the wrong thread. > It seems bad that a MessagePort would be used on one thread but could be > destroyed on another thread while being used. Brady is more familiar with > this code however. A MessagePort has no thread-safe members. But we would be touching ScriptExecutionContext message port hashset from various threads which probably has implications. > > Source/WebCore/dom/MessagePort.cpp:80 > > + callback(allMessagePorts().get(identifier)); > > This could in theory cause deadlocks if the callback calls > existingMessagePortForIdentifier(). Yes, the other approach would be to somehow take the lock from the caller site. Not a problem right now but might be in the future. Maybe there is a better way to do this?
Radar WebKit Bug Importer
Comment 5 2018-02-22 15:48:46 PST
youenn fablet
Comment 6 2018-02-23 07:22:13 PST
I will update the patch to add the various getters/setter methods with a lock and remove the need for the existingXX method. Will do that tonight
youenn fablet
Comment 7 2018-02-25 16:08:47 PST
youenn fablet
Comment 8 2018-02-25 16:18:28 PST
I added two methods isExistingMessagePortLocallyReachable and notifyMessageAvailable. I wonder whether we could simplify the MessagePort model a bit. Maybe something like having a MainThread map that allows getting from a message port identifier the context identifier and whether it is locally reachable. That may allow removing the need of the lock and making MessagePort a regular RefCounted object.
Chris Dumez
Comment 9 2018-02-26 09:22:01 PST
Comment on attachment 334586 [details] Patch r=me, nice.
WebKit Commit Bot
Comment 10 2018-02-26 10:01:16 PST
Comment on attachment 334586 [details] Patch Clearing flags on attachment: 334586 Committed r229028: <https://trac.webkit.org/changeset/229028>
WebKit Commit Bot
Comment 11 2018-02-26 10:01:18 PST
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.