Bug 234890 - ReadableStream::lock should check whether there is an exception when getting ReadableStreamDefaultReader private constructor
Summary: ReadableStream::lock should check whether there is an exception when getting ...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore Misc. (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: youenn fablet
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2022-01-05 11:08 PST by youenn fablet
Modified: 2022-01-06 12:15 PST (History)
7 users (show)

See Also:


Attachments
Patch (1.88 KB, patch)
2022-01-05 11:10 PST, youenn fablet
no flags Details | Formatted Diff | Diff
Patch (8.26 KB, patch)
2022-01-06 05:07 PST, youenn fablet
no flags Details | Formatted Diff | Diff
Patch for landing (8.24 KB, patch)
2022-01-06 11:37 PST, youenn fablet
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description youenn fablet 2022-01-05 11:08:09 PST
ReadableStream::lock should check whether there is an exception when getting ReadableStreamDefaultReader private constructor
Comment 1 youenn fablet 2022-01-05 11:10:22 PST
Created attachment 448410 [details]
Patch
Comment 2 Frédéric Wang (:fredw) 2022-01-06 00:49:46 PST
Comment on attachment 448410 [details]
Patch

LGTM. Do we have a non-regression test for that? IIUC, the current return-if-exception line is not covered by our tests since otherwise it would currently crash when JSC::asObject is called?
Comment 3 youenn fablet 2022-01-06 02:55:55 PST
(In reply to Frédéric Wang (:fredw) from comment #2)
> Comment on attachment 448410 [details]
> Patch
> 
> LGTM. Do we have a non-regression test for that? IIUC, the current
> return-if-exception line is not covered by our tests since otherwise it
> would currently crash when JSC::asObject is called?

I'll try to write one.
Comment 4 youenn fablet 2022-01-06 03:38:31 PST
(In reply to youenn fablet from comment #3)
> (In reply to Frédéric Wang (:fredw) from comment #2)
> > Comment on attachment 448410 [details]
> > Patch
> > 
> > LGTM. Do we have a non-regression test for that? IIUC, the current
> > return-if-exception line is not covered by our tests since otherwise it
> > would currently crash when JSC::asObject is called?
> 
> I'll try to write one.

I tried to write one but I am not able to trigger the crash, using something like:
  const request = new Request("http://test.org", {"method": "POST", "body": "text" });
  request.text();
  request.body;

I'll rewrite the patch to share the code and check between the two paths.
Comment 5 youenn fablet 2022-01-06 05:07:03 PST
Created attachment 448487 [details]
Patch
Comment 6 youenn fablet 2022-01-06 05:08:00 PST
I was able to write a test and added it in addition to write the utility function. @fredw, PTAL.
Comment 7 Frédéric Wang (:fredw) 2022-01-06 05:46:34 PST
Comment on attachment 448487 [details]
Patch

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

still LGTM but since this is a bigger refactoring, I'd prefer Mark Lam to check.

> Source/WebCore/bindings/js/ReadableStream.cpp:-120
> -    auto scope = DECLARE_CATCH_SCOPE(vm);

In the past, there was a catch scope here but I'm not sure why since I don't see any explicit clearing of exceptions.

> Source/WebCore/bindings/js/ReadableStream.cpp:135
> +        args.append(readableStream());

I guess you should keep ASSERT(!args.hasOverflowed()) here?

> LayoutTests/ChangeLog:9
> +        * streams/readable-stream-lock-after-worker-terminates-crash.html: Added.

So this new test is crashing in ReadableStream::lock without your patch right? Just to be sure since the crashing cast operation is now shared in invokeConstructor... I believe ReadableStream::create is already covered by streams/readable-stream-create-after-worker-terminates-crash.html

> LayoutTests/streams/readable-stream-lock-after-worker-terminates-crash.html:11
> +    const worker = new Worker('data:application/javascript;charset=utf-8,' + createRequest.toString() + ';createRequest()');

nit: you can probably use backticks here too.
Comment 8 Frédéric Wang (:fredw) 2022-01-06 05:50:19 PST
Comment on attachment 448487 [details]
Patch

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

> Source/WebCore/bindings/js/ReadableStream.cpp:48
> +    EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException());

I also forgot to say, in the past ReadableStream::create was not asserting for non-termination exception, but again I'm not sure whether such an exception could happen.
Comment 9 Mark Lam 2022-01-06 09:01:48 PST
Comment on attachment 448487 [details]
Patch

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

I have some comments below but LGTM too.

> Source/WebCore/bindings/js/ReadableStream.cpp:40
> +static inline ExceptionOr<JSObject*> invokeConstructor(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier, const Function<void(MarkedArgumentBuffer&, JSC::JSGlobalObject&, JSDOMGlobalObject&)>& buildArguments)

nit: since you have declared `using namespace JSC` above, I think you can drop all the `JSC::` qualifiers here and below.  It'll make the code a lot more readable.

>> Source/WebCore/bindings/js/ReadableStream.cpp:48
>> +    EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException());
> 
> I also forgot to say, in the past ReadableStream::create was not asserting for non-termination exception, but again I'm not sure whether such an exception could happen.

It can happen if the property being fetched from the globalObject is a lazy property which may entail some complex code.

Given the RETURN_IF_EXCEPTION below, I'd almost say that this EXCEPTION_ASSERT is not necessary for exception check validation.  However, it does serve a purpose to document an invariant that we're not expecting any exception to be thrown here other than the TerminationException.  So, I think it's good to keep it.

>> Source/WebCore/bindings/js/ReadableStream.cpp:-120
>> -    auto scope = DECLARE_CATCH_SCOPE(vm);
> 
> In the past, there was a catch scope here but I'm not sure why since I don't see any explicit clearing of exceptions.

This was a bug.  Since there's a possibility of a TerminationException, the use of a CatchScope here was incorrect.  This patch is doing the right thing.

>> Source/WebCore/bindings/js/ReadableStream.cpp:135
>> +        args.append(readableStream());
> 
> I guess you should keep ASSERT(!args.hasOverflowed()) here?

Or you can move ASSERT(!args.hasOverflowed()) to after the call to buildArguments() in invokeConstructor().  Asserting it here would be nicer as the crash trace will point to which call to invokeConstructor() caused the assertion failure.
Comment 10 youenn fablet 2022-01-06 11:37:48 PST
Created attachment 448514 [details]
Patch for landing
Comment 11 EWS 2022-01-06 12:14:43 PST
Committed r287711 (245796@main): <https://commits.webkit.org/245796@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 448514 [details].
Comment 12 Radar WebKit Bug Importer 2022-01-06 12:15:22 PST
<rdar://problem/87213143>