Bug 129896

Summary: CoreIPC deadlocks when actively using LocalStorage
Product: WebKit Reporter: Mariusz Nowak <medikoo+webkit.org>
Component: WebKit2Assignee: Nobody <webkit-unassigned>
Status: RESOLVED DUPLICATE    
Severity: Major CC: andersca, ap, bburg, beidson
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
URL: http://ldz-test4.medyk.org
See Also: https://bugs.webkit.org/show_bug.cgi?id=149585

Description Mariusz Nowak 2014-03-07 12:10:05 PST
I work with single-page application in which following happens when user tries to login: XMLHttpRequest is send, and on success at same time data form server is send via Server Sent Events channel. After given data is received page is reloaded. When there's larger amounts of data sent via Server Sent Events channel, page starts being unresponsive beyond recovery. There's no chance to access its console, and there's no CPU activity that could be blamed for lock.

I tracked it as far as I could, an it looks to be directly related to XMLHttpRequest instance being in InvalidState (for really no reason).

To reproduce the case

1. Get into http://ldz-test4.medyk.org/ it's dev version with not minified scripts so you can more easily track what's going in
2. Open Web Inspector with console visible
3. Login (blue "INGRESE" button in top right corner) with email: mariusz@medikoo.com password: 11111q
4. It should work fine, still you already should notice some invalid states of Xhr reported in a console, that already should not happen.
5. Logout (Red switch in top right corner)
7. Login again but this time with user for which bigger amount of data is loaded: email: supermario@ldz.org password: abc123
8. Most likely page will hang, either during Xhr call or shortly after

After you reload you'll appear logged in, you can repeat that by logging out and switching to other user and so on (to assure big data flow in SSE channel you need to login with other user than one that was logged in before).

This happens only in WebKit (including latest Safari). Other browsers in they're major version, work excellent.
 
Worst is, that I don't have idea how to workaround it, so with this bug on I can't provide proper support for Safari.
Comment 1 BJ Burg 2014-03-10 16:14:51 PDT
You'll need to attach a smaller test case before anyone can investigate this further.

Is this a synchronous or async XHR call?

Does it hang when the inspector is closed, or only when open?
Comment 2 Mariusz Nowak 2014-03-11 01:25:07 PDT
I'd love to prepare smaller test case, but I'm not able. It looks it's related to how process is busy with other things.

It doesn't depend on console being open. Although as console slows down process, error happens more likely when it's open.

I explained how you can reproduce it in 100% reliable way, and you have access to specially added logs and readable code.

Code related to problematic XMLHttpRequest call is just below few lines (21567 - 21606) of user.js file:

	var xhr = new XMLHttpRequest(), def = deferred(), interval;

	console.log("Initialize Xhr", url);
	xhr.open(method, url, true);
	xhr.onload = function () {
		var type;
		console.log("Xhr loaded!");
		clearInterval(interval);
		if ((xhr.status < 200) && (xhr.status >= 300)) {
			def.reject(new Error(xhr.responseText));
			return;
		}
		type = getType(xhr);
		if (type === 'application/json') {
			def.resolve(parse(xhr.response));
			return;
		}
		def.resolve(xhr.response);
	};
	xhr.onerror = function () { def.reject(new Error("Error occured")); };
	xhr.onabort = function () { def.reject(new Error("Operation aborted")); };
	xhr.upload.onabort = xhr.onabort;

	xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
	if (method === 'POST') {
		xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		xhr.send(stringify(data));
	} else {
		xhr.send();
	}

	interval = setInterval(function () {
		try {
			xhr.status;
		} catch (e) {
			console.error("Xhr status: Not accessible [" + e.message + "]");
			return;
		}
		console.log("Xhr status: OK");
	}, 100);
Comment 3 Mariusz Nowak 2014-03-11 01:27:55 PDT
As I mentioned, this XMLHttpRequest invalid state issue, happens only in WebKit/Safari, all other browsers (Firefox, Chrome, IE and also Opera) work 100% fine without a glitch.
Comment 4 Alexey Proskuryakov 2014-04-09 11:31:16 PDT
I can reproduce this. What happens here is that WebProcess sends a synchronous WebPageProxy::DecidePolicyForNavigationAction message to UI process, but never gets a response. UI process is completely idle, it simply drops the message on the floor! This is very very bad, and very surprising.

Unfortunately, the site is unusable in debug builds - it runs some ultra heavy JavaScripts, so pages take minutes to load, and even then, the bug doesn't seem to occur. So this will be a challenge to investigate.

Notably, we are not hitting any resource load limits, I didn't see NetworkProcess get more than 4-5 loads at a time.
Comment 5 Alexey Proskuryakov 2014-04-09 11:41:33 PDT
There is one code path where Connection fails to send a sync response, I can check if it's taken here.

void Connection::dispatchMessage(std::unique_ptr<MessageDecoder> message)
{
    // If there's no client, return. We do this after calling releaseArguments so that
    // the ArgumentDecoder message will be freed.
    if (!m_client)
        return;
Comment 6 Alexey Proskuryakov 2014-04-09 12:13:28 PDT
No, this is not it - DecidePolicyForNavigationAction doesn't reach Connection::dispatchMessage.
Comment 7 Alexey Proskuryakov 2014-04-09 13:16:06 PDT
Both WebProcess and UIProcess are actually stuck inside mach_msg() in Connection::sendOutgoingMessage(). WebProcess is trying to send a SetItem message, and UIProcess is trying to send a DidSetItem message (or potentially DispatchStorageEvent).

When both processes are sending messages on the IPC.ReceiveQueue thread, they are not receiving messages, so there is no chance to get out of this deadlock.

Perhaps we should add a timeout to mach_msg, and try receiving messages for a while if we can't send? Or use separate threads for sending and receiving?
Comment 8 Alexey Proskuryakov 2014-04-09 13:19:15 PDT
<rdar://problem/16569272>
Comment 9 Anders Carlsson 2014-04-17 11:55:56 PDT
There's a new dispatch source that can be used to know when it's possible to send messages without blocking - I think we can use that.
Comment 10 Mariusz Nowak 2016-03-30 02:40:45 PDT
Are there any news on that one? It's still observable in Safari 9.1
Comment 11 Anders Carlsson 2016-12-13 12:58:55 PST
This should be fixed with the fix for https://bugs.webkit.org/show_bug.cgi?id=165622
Comment 12 Mariusz Nowak 2016-12-14 00:40:41 PST
Possibly https://bugs.webkit.org/show_bug.cgi?id=149585 is a duplicate of this one
Comment 13 Alexey Proskuryakov 2016-12-14 09:26:09 PST

*** This bug has been marked as a duplicate of bug 165622 ***