Bug 94677 - http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html fails, triggering an assertion in JSEventListener::jsFunction
Summary: http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html fail...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore JavaScript (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mike West
URL:
Keywords: Qt, QtTriaged
Depends on:
Blocks: 89440
  Show dependency treegraph
 
Reported: 2012-08-22 01:10 PDT by Balazs Ankes
Modified: 2012-09-17 02:04 PDT (History)
12 users (show)

See Also:


Attachments
Patch (4.95 KB, patch)
2012-09-13 02:09 PDT, Mike West
no flags Details | Formatted Diff | Diff
Unskipping crashing test. (7.25 KB, patch)
2012-09-13 05:08 PDT, Mike West
no flags Details | Formatted Diff | Diff
Patch (10.31 KB, patch)
2012-09-13 11:54 PDT, Mike West
no flags Details | Formatted Diff | Diff
it's -> its (10.31 KB, patch)
2012-09-13 11:58 PDT, Mike West
no flags Details | Formatted Diff | Diff
Jochen's feedback. (9.80 KB, patch)
2012-09-13 12:17 PDT, Mike West
no flags Details | Formatted Diff | Diff
Function. (9.81 KB, patch)
2012-09-13 22:57 PDT, Mike West
no flags Details | Formatted Diff | Diff
Hrm. (11.76 KB, patch)
2012-09-14 11:33 PDT, Mike West
no flags Details | Formatted Diff | Diff
Fewer curly bits. (11.78 KB, patch)
2012-09-14 14:11 PDT, Mike West
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Balazs Ankes 2012-08-22 01:10:35 PDT
--- /ramdisk/qt-linux-64-release/build/layout-test-results/http/tests/security/contentSecurityPolicy/register-bypassing-scheme-expected.txt 
+++ /ramdisk/qt-linux-64-release/build/layout-test-results/http/tests/security/contentSecurityPolicy/register-bypassing-scheme-actual.txt 
@@ -1,8 +1,4 @@
 CONSOLE MESSAGE: Refused to load the image 'http://127.0.0.1:8000/security/resources/abe.png' because it violates the following Content Security Policy directive: "img-src https:".
 
-ALERT: PASS (1/3)
-ALERT: PASS (2/3)
-CONSOLE MESSAGE: Refused to load the image 'http://127.0.0.1:8000/security/resources/abe.png' because it violates the following Content Security Policy directive: "img-src https:".
-
-ALERT: PASS (3/3)
+FAIL: Timed out waiting for notifyDone to be called
 This test ensures that registering a scheme as bypassing CSP actually bypasses CSP. This test passes if three PASSes are generated.
Comment 1 Zan Dobersek 2012-08-22 01:58:49 PDT
On GTK the test always passes in the retry run. Seems there's a test that's run before this one that puts the environment into a specific state in which the test then fails.

On QT, in retry, it still fails, but there's another CSP test run before it[1]:
http/tests/security/contentSecurityPolicy/object-src-url-allowed.html
http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html
...

Perhaps the test runners are not resetting something properly between each test?

[1] - http://build.webkit.org/results/Qt%20Linux%20Release/r126259%20(51094)/retries/tests_run0.txt
Comment 2 Balazs Ankes 2012-08-22 02:18:37 PDT
Skip committed in r126282. Please unskip it with proper fix.
Comment 3 Zan Dobersek 2012-08-22 14:19:58 PDT
I can confirm that the test fails on GTK consistently when the test list consists of the two tests mentioned in comment #1. The test then passes when run singly.

The issue when the test times out is that while the error occurs and the error timer is set to dispatch soon, the ImageLoader object gets deleted and aborts the error event firing. As to why or how the preceding test would make this happen, I have no idea.
Comment 4 Alexey Proskuryakov 2012-09-12 13:21:46 PDT
This test now fails on Mac bots too. In debug builds, it fails with an assertion:


Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000bbadbeef

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   com.apple.WebCore             	0x000000010963d9f9 WebCore::JSEventListener::jsFunction(WebCore::ScriptExecutionContext*) const + 329 (JSEventListener.h:90)
1   com.apple.WebCore             	0x00000001097b5b02 WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) + 194 (JSEventListener.cpp:80)
2   com.apple.WebCore             	0x00000001091eca67 WebCore::EventTarget::fireEventListeners(WebCore::Event*, WebCore::EventTargetData*, WTF::Vector<WebCore::RegisteredEventListener, 1ul>&) + 359 (EventTarget.cpp:232)
3   com.apple.WebCore             	0x00000001091ec8c5 WebCore::EventTarget::fireEventListeners(WebCore::Event*) + 325 (EventTarget.cpp:200)
4   com.apple.WebCore             	0x0000000109c9cd4b WebCore::Node::handleLocalEvents(WebCore::Event*) + 155 (Node.cpp:2546)
5   com.apple.WebCore             	0x00000001091bff64 WebCore::EventContext::handleLocalEvents(WebCore::Event*) const + 276 (EventContext.cpp:55)
6   com.apple.WebCore             	0x00000001091c2ab9 WebCore::EventDispatcher::dispatchEventAtTarget(WTF::PassRefPtr<WebCore::Event>) + 89 (EventDispatcher.cpp:309)
Comment 5 Alexey Proskuryakov 2012-09-12 16:35:15 PDT
Reproducible with just 

run-webkit-tests -v http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html --repeat-each 20
Comment 6 Alexey Proskuryakov 2012-09-12 17:25:35 PDT
I had a brief look at this. So, there is an error event being fired on HTMLImageElement after its listener's JavaScript wrapper has been collected.

The code that tells whether it's OK to garbage collect is isReachableFromDOM() in JSNodeCustom.cpp. It basically looks at hasPendingLoadEvent(), which I think is a misnomer, as it should be covering error, too. The code hasn't been changed much in months (I think that Adam last touched it in March, to improve the naming).

Mike, does CSP first stop the load, and then post an error event on a timer perhaps? That would let garbage collection perform collection too early.
Comment 7 Mike West 2012-09-12 22:07:03 PDT
(In reply to comment #6)
> I had a brief look at this. So, there is an error event being fired on HTMLImageElement after its listener's JavaScript wrapper has been collected.
> 
> The code that tells whether it's OK to garbage collect is isReachableFromDOM() in JSNodeCustom.cpp. It basically looks at hasPendingLoadEvent(), which I think is a misnomer, as it should be covering error, too. The code hasn't been changed much in months (I think that Adam last touched it in March, to improve the naming).
> 
> Mike, does CSP first stop the load, and then post an error event on a timer perhaps? That would let garbage collection perform collection too early.

Yes, the load is blocked, and then the error is fired asynchronously.

I'll take a look at this issue today. Would a synchronous event trigger be acceptable? If not, perhaps I can adjust the isReachableFromDOM method to understand that an element has waiting events?
Comment 8 Mike West 2012-09-13 01:26:37 PDT
(In reply to comment #7)
> I'll take a look at this issue today. Would a synchronous event trigger be acceptable? If not, perhaps I can adjust the isReachableFromDOM method to understand that an element has waiting events?

Now that I'm looking at the code, the former option is stupid. :) I'll adjust hasPendingLoadEvent to check the error event sender as well. That looks straightforward.
Comment 9 Mike West 2012-09-13 02:09:01 PDT
Created attachment 163819 [details]
Patch
Comment 10 Mike West 2012-09-13 02:09:44 PDT
(In reply to comment #9)
> Created an attachment (id=163819) [details]
> Patch

Jochen, perhaps you could take a look at this before California wakes up? :)
Comment 11 Mike West 2012-09-13 05:08:16 PDT
Created attachment 163843 [details]
Unskipping crashing test.
Comment 12 jochen 2012-09-13 07:00:49 PDT
Comment on attachment 163843 [details]
Unskipping crashing test.

This looks correct.

Let's wait whether Alexey and Adam agree.
Comment 13 Alexey Proskuryakov 2012-09-13 08:36:06 PDT
Comment on attachment 163843 [details]
Unskipping crashing test.

View in context: https://bugs.webkit.org/attachment.cgi?id=163843&action=review

Looks reasonable to me. I'd like to wait for Adam's comments, because (1) he was the last one to meaningfully update this code in March, and (2) his recent patch is blamed for this assertion firing elsewhere, mysteriously to me (see bug 93654).

> Source/WebCore/ChangeLog:9
> +        element before reclaiming it's memory. It's not, however, checking that

First "it's" should be "its".

> Source/WebCore/ChangeLog:20
> +        This new behavior is covered by existing tests. In particular,
> +        http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html
> +        should no longer crash.

The existing tests only catch this once in multiple runs, it would be good to have a test that hits the issue reliably.
Comment 14 Adam Barth 2012-09-13 08:43:15 PDT
> The existing tests only catch this once in multiple runs, it would be good to have a test that hits the issue reliably.

You might be able to do that by explicitly calling gc() at an opportune time.  There's a gc.js script somewhere in LayoutTests that makes this easy.
Comment 15 Kentaro Hara 2012-09-13 08:45:13 PDT
(In reply to comment #14)
> You might be able to do that by explicitly calling gc() at an opportune time.  There's a gc.js script somewhere in LayoutTests that makes this easy.

FYI, fast/js/resources/js-test-pre.js has gc().
Comment 16 Mike West 2012-09-13 09:10:16 PDT
(In reply to comment #15)
> (In reply to comment #14)
> > You might be able to do that by explicitly calling gc() at an opportune time.  There's a gc.js script somewhere in LayoutTests that makes this easy.
> 
> FYI, fast/js/resources/js-test-pre.js has gc().

Thanks all. I'll see what I can do about reproducing the crash every time. That will be a nice change of pace from ensuring that crashes never reproduce. :)
Comment 17 Mike West 2012-09-13 11:34:05 PDT
(In reply to comment #5)
> Reproducible with just 
> 
> run-webkit-tests -v http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html --repeat-each 20

I'm having issues reproducing this locally, with or without gc(). Alexey, you were reproducing it on the plain old mac port, right? Release or debug build? Nothing else interesting about the config?
Comment 18 Mike West 2012-09-13 11:47:48 PDT
(In reply to comment #17)
> (In reply to comment #5)
> > Reproducible with just 
> > 
> > run-webkit-tests -v http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html --repeat-each 20
> 
> I'm having issues reproducing this locally, with or without gc(). Alexey, you were reproducing it on the plain old mac port, right? Release or debug build? Nothing else interesting about the config?

Ah. Amusing. I couldn't reproduce because I had this patch applied. :)

I'll upload a new patch in a moment that GC's the heck out of register-bypassing-scheme.
Comment 19 Mike West 2012-09-13 11:54:26 PDT
Created attachment 163924 [details]
Patch
Comment 20 Mike West 2012-09-13 11:58:57 PDT
Created attachment 163926 [details]
it's -> its
Comment 21 jochen 2012-09-13 11:59:16 PDT
Comment on attachment 163924 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=163924&action=review

> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:6
> +    // Copied from fast/js/resources/js-test-pre.js, which isn't available via HTTP.

it's in http://127.0.0.1:8000/resources/js-test-pre.js
Comment 22 Mike West 2012-09-13 12:17:24 PDT
Created attachment 163932 [details]
Jochen's feedback.
Comment 23 Mike West 2012-09-13 12:22:53 PDT
Comment on attachment 163932 [details]
Jochen's feedback.

Cool. Adam, Alexey, CQ?
Comment 24 Alexey Proskuryakov 2012-09-13 12:47:40 PDT
I can't easily wrap my head around the existing nonsense code. Adam?

One thing that I'm not entirely sure about is regular failing loads. Why are we not seeing this assertion failure when image load fails because of a 404 or a network issue? Is CSP different in some way - or perhaps this could be reproduced with a regular failing load, and we just horribly lack in test coverage?
Comment 25 Adam Barth 2012-09-13 15:11:17 PDT
Comment on attachment 163932 [details]
Jochen's feedback.

View in context: https://bugs.webkit.org/attachment.cgi?id=163932&action=review

> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:21
> +        setTimeout(gc, 0);

Doesn't this race with the image loads?
Comment 26 Adam Barth 2012-09-13 15:13:45 PDT
Comment on attachment 163932 [details]
Jochen's feedback.

View in context: https://bugs.webkit.org/attachment.cgi?id=163932&action=review

>> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:21
>> +        setTimeout(gc, 0);
> 
> Doesn't this race with the image loads?

One solution is to kick off the load in a separate function and then call gc() after returning from that function.  The events should then be delivered asynchronously.
Comment 27 Mike West 2012-09-13 15:20:23 PDT
(In reply to comment #26)
> (From update of attachment 163932 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=163932&action=review
> 
> >> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:21
> >> +        setTimeout(gc, 0);
> > 
> > Doesn't this race with the image loads?
> 
> One solution is to kick off the load in a separate function and then call gc() after returning from that function.  The events should then be delivered asynchronously.

Something like this?
    
    (function x() { img.src = "whatever"; })();
    gc();

I somehow thought that's more or less what the setTimeout(..., 0) was doing.
Comment 28 Adam Barth 2012-09-13 16:12:25 PDT
> Something like this?
> 
>     (function x() { img.src = "whatever"; })();
>     gc();

Yes.  (Note the "x" isn't needed.)

> I somehow thought that's more or less what the setTimeout(..., 0) was doing.

It is similar, but the difference is that in the setTimeout approach, you don't know when the gc will actually run.  It gets scheduled on the event loop, but it might happen before or after the load and/or error tests happen.
Comment 29 Mike West 2012-09-13 22:57:13 PDT
Created attachment 164052 [details]
Function.
Comment 30 Mike West 2012-09-13 22:58:06 PDT
(In reply to comment #28)
> > Something like this?
> > 
> >     (function x() { img.src = "whatever"; })();
> >     gc();
> 
> Yes.  (Note the "x" isn't needed.)
> 
> > I somehow thought that's more or less what the setTimeout(..., 0) was doing.
> 
> It is similar, but the difference is that in the setTimeout approach, you don't know when the gc will actually run.  It gets scheduled on the event loop, but it might happen before or after the load and/or error tests happen.

Thanks for the explanation.  That makes sense. The newly attached patch implements the suggestion.
Comment 31 Adam Barth 2012-09-14 00:17:32 PDT
Comment on attachment 164052 [details]
Function.

View in context: https://bugs.webkit.org/attachment.cgi?id=164052&action=review

> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:21
> +        var img = document.createElement('img');
> +        img.onload = function () {
> +            alert('FAIL (1/1)');
> +            finishTesting();
> +        };
> +        img.onerror = function () {
> +            alert('PASS (1/1)');
> +            finishTesting();
> +        };
> +        (function () { img.src = "../resources/abe.png"; })();
> +        gc();

This won't work quite right.  You need to put all references to img inside the function so that img will be garbage by the time you call gc().  Does this test successfully replicate the failure?
Comment 32 Mike West 2012-09-14 01:22:24 PDT
(In reply to comment #24)
> I can't easily wrap my head around the existing nonsense code. Adam?
> 
> One thing that I'm not entirely sure about is regular failing loads. Why are we not seeing this assertion failure when image load fails because of a 404 or a network issue? Is CSP different in some way - or perhaps this could be reproduced with a regular failing load, and we just horribly lack in test coverage?

On IRC, Jochen proposed that we add at least one more test to this patch to check this case. I'll take care of that sometime in the vaguely near future, along with Adam's note from below.

Thanks!
Comment 33 Mike West 2012-09-14 11:33:24 PDT
Created attachment 164198 [details]
Hrm.
Comment 34 Mike West 2012-09-14 11:34:35 PDT
(In reply to comment #32)

> On IRC, Jochen proposed that we add at least one more test to this patch to check this case. I'll take care of that sometime in the vaguely near future, along with Adam's note from below.

I've added a test similar to what I'd talked about with Jochen, but I couldn't get it to crash, with or without the patch. That's good, I suppose! Or, it's proof that I misunderstood Jochen's suggestion.

Mind taking a look?
Comment 35 Adam Barth 2012-09-14 13:13:18 PDT
Comment on attachment 164198 [details]
Hrm.

View in context: https://bugs.webkit.org/attachment.cgi?id=164198&action=review

> LayoutTests/http/tests/security/contentSecurityPolicy/img-blocked-no-gc-crash.html:27
> +        if (window.testRunner) {

No need for { } in this if
Comment 36 Adam Barth 2012-09-14 13:14:06 PDT
Interesting.  I'm inclined to say we should land this patch with the extra test.  @jochen: What do you think?
Comment 37 Mike West 2012-09-14 14:11:07 PDT
Created attachment 164223 [details]
Fewer curly bits.
Comment 38 Mike West 2012-09-14 14:12:11 PDT
(In reply to comment #36)
> Interesting.  I'm inclined to say we should land this patch with the extra test.  @jochen: What do you think?

Cool. Uploaded a final(?) patch without the superfluous braces. If you're happy with the test Jochen, CQ?
Comment 39 WebKit Review Bot 2012-09-17 02:04:50 PDT
Comment on attachment 164223 [details]
Fewer curly bits.

Clearing flags on attachment: 164223

Committed r128730: <http://trac.webkit.org/changeset/128730>
Comment 40 WebKit Review Bot 2012-09-17 02:04:57 PDT
All reviewed patches have been landed.  Closing bug.