Title: [272166] trunk
Revision
272166
Author
[email protected]
Date
2021-02-01 12:36:31 -0800 (Mon, 01 Feb 2021)

Log Message

ReadableStream C++ methods should check for exception
https://bugs.webkit.org/show_bug.cgi?id=215376
<rdar://problem/66816192>

Reviewed by Alex Christensen.

Source/WebCore:

Refactor code to catch and handle exceptions in case of ReadableStream methods.
Exceptions can happen in case of worker being abruptly terminated, which can only be tested flakily.

In case of tee, if an exception happens, we return a WTF::nullopt.

Test: streams/readable-stream-tee-worker.html

* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::clone):
* bindings/js/ReadableStream.cpp:
(WebCore::invokeReadableStreamFunction):
(WebCore::ReadableStream::pipeTo):
(WebCore::ReadableStream::tee):
(WebCore::ReadableStream::lock):
(WebCore::checkReadableStream):
* bindings/js/ReadableStream.h:

LayoutTests:

* streams/readable-stream-tee-worker-expected.txt: Added.
* streams/readable-stream-tee-worker.html: Added.
* streams/readable-stream-tee.js: Added.
(teeRepetitively):
(test):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (272165 => 272166)


--- trunk/LayoutTests/ChangeLog	2021-02-01 20:30:42 UTC (rev 272165)
+++ trunk/LayoutTests/ChangeLog	2021-02-01 20:36:31 UTC (rev 272166)
@@ -1,3 +1,17 @@
+2021-02-01  Youenn Fablet  <[email protected]>
+
+        ReadableStream C++ methods should check for exception
+        https://bugs.webkit.org/show_bug.cgi?id=215376
+        <rdar://problem/66816192>
+
+        Reviewed by Alex Christensen.
+
+        * streams/readable-stream-tee-worker-expected.txt: Added.
+        * streams/readable-stream-tee-worker.html: Added.
+        * streams/readable-stream-tee.js: Added.
+        (teeRepetitively):
+        (test):
+
 2021-02-01  Sihui Liu  <[email protected]>
 
         Use user media permission prompt for speech recognition

Added: trunk/LayoutTests/streams/readable-stream-tee-worker-expected.txt (0 => 272166)


--- trunk/LayoutTests/streams/readable-stream-tee-worker-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/streams/readable-stream-tee-worker-expected.txt	2021-02-01 20:36:31 UTC (rev 272166)
@@ -0,0 +1,3 @@
+
+PASS Tee a ReadableStream in worker
+

Added: trunk/LayoutTests/streams/readable-stream-tee-worker.html (0 => 272166)


--- trunk/LayoutTests/streams/readable-stream-tee-worker.html	                        (rev 0)
+++ trunk/LayoutTests/streams/readable-stream-tee-worker.html	2021-02-01 20:36:31 UTC (rev 272166)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script src=''></script>
+<script src=''></script>
+<script>
+'use strict';
+fetch_tests_from_worker(new Worker('readable-stream-tee.js'));
+</script>

Added: trunk/LayoutTests/streams/readable-stream-tee.js (0 => 272166)


--- trunk/LayoutTests/streams/readable-stream-tee.js	                        (rev 0)
+++ trunk/LayoutTests/streams/readable-stream-tee.js	2021-02-01 20:36:31 UTC (rev 272166)
@@ -0,0 +1,20 @@
+'use strict';
+
+if (self.importScripts) {
+    self.importScripts('../resources/testharness.js');
+}
+
+function teeRepetitively(stream)
+{
+    const [t1, t2] = stream.tee();
+    setTimeout(() => {
+        teeRepetitively(t1);
+    }, 0);
+}
+
+test(function() {
+    const stream = new ReadableStream({ start: () => { } });
+    teeRepetitively(stream);
+}, "Tee a ReadableStream in worker");
+
+done();

Modified: trunk/Source/WebCore/ChangeLog (272165 => 272166)


--- trunk/Source/WebCore/ChangeLog	2021-02-01 20:30:42 UTC (rev 272165)
+++ trunk/Source/WebCore/ChangeLog	2021-02-01 20:36:31 UTC (rev 272166)
@@ -1,3 +1,28 @@
+2021-02-01  Youenn Fablet  <[email protected]>
+
+        ReadableStream C++ methods should check for exception
+        https://bugs.webkit.org/show_bug.cgi?id=215376
+        <rdar://problem/66816192>
+
+        Reviewed by Alex Christensen.
+
+        Refactor code to catch and handle exceptions in case of ReadableStream methods.
+        Exceptions can happen in case of worker being abruptly terminated, which can only be tested flakily.
+
+        In case of tee, if an exception happens, we return a WTF::nullopt.
+
+        Test: streams/readable-stream-tee-worker.html
+
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::clone):
+        * bindings/js/ReadableStream.cpp:
+        (WebCore::invokeReadableStreamFunction):
+        (WebCore::ReadableStream::pipeTo):
+        (WebCore::ReadableStream::tee):
+        (WebCore::ReadableStream::lock):
+        (WebCore::checkReadableStream):
+        * bindings/js/ReadableStream.h:
+
 2021-02-01  Sihui Liu  <[email protected]>
 
         Use user media permission prompt for speech recognition

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (272165 => 272166)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2021-02-01 20:30:42 UTC (rev 272165)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2021-02-01 20:36:31 UTC (rev 272166)
@@ -330,8 +330,10 @@
 
     if (m_readableStream) {
         auto clones = m_readableStream->tee();
-        m_readableStream = WTFMove(clones.first);
-        clone.m_readableStream = WTFMove(clones.second);
+        if (clones) {
+            m_readableStream = WTFMove(clones->first);
+            clone.m_readableStream = WTFMove(clones->second);
+        }
     }
     return clone;
 }

Modified: trunk/Source/WebCore/bindings/js/ReadableStream.cpp (272165 => 272166)


--- trunk/Source/WebCore/bindings/js/ReadableStream.cpp	2021-02-01 20:30:42 UTC (rev 272165)
+++ trunk/Source/WebCore/bindings/js/ReadableStream.cpp	2021-02-01 20:36:31 UTC (rev 272166)
@@ -61,51 +61,51 @@
     return create(globalObject, *jsCast<JSReadableStream*>(object));
 }
 
-namespace ReadableStreamInternal {
-static inline JSC::JSValue callFunction(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue jsFunction, JSC::JSValue thisValue, const JSC::ArgList& arguments)
+static inline Optional<JSC::JSValue> invokeReadableStreamFunction(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier, JSC::JSValue thisValue, const JSC::MarkedArgumentBuffer& arguments)
 {
-    VM& vm = lexicalGlobalObject.vm();
+    JSC::VM& vm = lexicalGlobalObject.vm();
+    JSC::JSLockHolder lock(vm);
+
+    auto function = lexicalGlobalObject.get(&lexicalGlobalObject, identifier);
+    ASSERT(function.isCallable(lexicalGlobalObject.vm()));
+
     auto scope = DECLARE_CATCH_SCOPE(vm);
-    auto callData = JSC::getCallData(vm, jsFunction);
-    ASSERT(callData.type != JSC::CallData::Type::None);
-    auto result = call(&lexicalGlobalObject, jsFunction, callData, thisValue, arguments);
-    scope.assertNoException();
+    auto callData = JSC::getCallData(vm, function);
+    auto result = call(&lexicalGlobalObject, function, callData, thisValue, arguments);
+    EXCEPTION_ASSERT(!scope.exception() || isTerminatedExecutionException(lexicalGlobalObject.vm(), scope.exception()));
+    if (scope.exception())
+        return { };
     return result;
 }
-}
 
 void ReadableStream::pipeTo(ReadableStreamSink& sink)
 {
     auto& lexicalGlobalObject = *m_globalObject;
-    JSVMClientData* clientData = static_cast<JSVMClientData*>(lexicalGlobalObject.vm().clientData);
-    const Identifier& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamPipeToPrivateName();
+    auto* clientData = static_cast<JSVMClientData*>(lexicalGlobalObject.vm().clientData);
+    auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamPipeToPrivateName();
 
-    auto readableStreamPipeTo = m_globalObject->get(&lexicalGlobalObject, privateName);
-    ASSERT(readableStreamPipeTo.isCallable(lexicalGlobalObject.vm()));
-
     MarkedArgumentBuffer arguments;
     arguments.append(readableStream());
     arguments.append(toJS(&lexicalGlobalObject, m_globalObject.get(), sink));
     ASSERT(!arguments.hasOverflowed());
-    ReadableStreamInternal::callFunction(lexicalGlobalObject, readableStreamPipeTo, JSC::jsUndefined(), arguments);
+    invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments);
 }
 
-std::pair<Ref<ReadableStream>, Ref<ReadableStream>> ReadableStream::tee()
+Optional<std::pair<Ref<ReadableStream>, Ref<ReadableStream>>> ReadableStream::tee()
 {
     auto& lexicalGlobalObject = *m_globalObject;
-    JSVMClientData* clientData = static_cast<JSVMClientData*>(lexicalGlobalObject.vm().clientData);
-    const Identifier& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamTeePrivateName();
+    auto* clientData = static_cast<JSVMClientData*>(lexicalGlobalObject.vm().clientData);
+    auto& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().readableStreamTeePrivateName();
 
-    auto readableStreamTee = m_globalObject->get(&lexicalGlobalObject, privateName);
-    ASSERT(readableStreamTee.isCallable(lexicalGlobalObject.vm()));
-
     MarkedArgumentBuffer arguments;
     arguments.append(readableStream());
     arguments.append(JSC::jsBoolean(true));
     ASSERT(!arguments.hasOverflowed());
-    auto returnedValue = ReadableStreamInternal::callFunction(lexicalGlobalObject, readableStreamTee, JSC::jsUndefined(), arguments);
+    auto returnedValue = invokeReadableStreamFunction(lexicalGlobalObject, privateName, JSC::jsUndefined(), arguments);
+    if (!returnedValue)
+        return { };
 
-    auto results = Detail::SequenceConverter<IDLInterface<ReadableStream>>::convert(lexicalGlobalObject, returnedValue);
+    auto results = Detail::SequenceConverter<IDLInterface<ReadableStream>>::convert(lexicalGlobalObject, *returnedValue);
 
     ASSERT(results.size() == 2);
     return std::make_pair(results[0].releaseNonNull(), results[1].releaseNonNull());
@@ -114,8 +114,10 @@
 void ReadableStream::lock()
 {
     auto& lexicalGlobalObject = *m_globalObject;
-    VM& vm = lexicalGlobalObject.vm();
+    auto& vm = lexicalGlobalObject.vm();
+#if ENABLE(EXCEPTION_SCOPE_VERIFICATION)
     auto scope = DECLARE_CATCH_SCOPE(vm);
+#endif
 
     auto& clientData = *static_cast<JSVMClientData*>(vm.clientData);
 
@@ -129,7 +131,7 @@
     ASSERT(!args.hasOverflowed());
 
     JSC::construct(&lexicalGlobalObject, constructor, constructData, args);
-    scope.assertNoException();
+    EXCEPTION_ASSERT(!scope.exception() || isTerminatedExecutionException(lexicalGlobalObject.vm(), scope.exception()));
 }
 
 static inline bool checkReadableStream(JSDOMGlobalObject& globalObject, JSReadableStream* readableStream, JSC::JSValue function)
@@ -140,7 +142,16 @@
     JSC::MarkedArgumentBuffer arguments;
     arguments.append(readableStream);
     ASSERT(!arguments.hasOverflowed());
-    return ReadableStreamInternal::callFunction(lexicalGlobalObject, function, JSC::jsUndefined(), arguments).isTrue();
+
+    auto& vm = lexicalGlobalObject.vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    auto callData = JSC::getCallData(vm, function);
+    ASSERT(callData.type != JSC::CallData::Type::None);
+
+    auto result = call(&lexicalGlobalObject, function, callData, JSC::jsUndefined(), arguments);
+    EXCEPTION_ASSERT(!scope.exception() || isTerminatedExecutionException(lexicalGlobalObject.vm(), scope.exception()));
+
+    return result.isTrue() || scope.exception();
 }
 
 bool ReadableStream::isLocked() const

Modified: trunk/Source/WebCore/bindings/js/ReadableStream.h (272165 => 272166)


--- trunk/Source/WebCore/bindings/js/ReadableStream.h	2021-02-01 20:30:42 UTC (rev 272165)
+++ trunk/Source/WebCore/bindings/js/ReadableStream.h	2021-02-01 20:36:31 UTC (rev 272166)
@@ -44,7 +44,7 @@
 
     WEBCORE_EXPORT static bool isDisturbed(JSC::JSGlobalObject&, JSC::JSValue);
 
-    std::pair<Ref<ReadableStream>, Ref<ReadableStream>> tee();
+    Optional<std::pair<Ref<ReadableStream>, Ref<ReadableStream>>> tee();
 
     void lock();
     void pipeTo(ReadableStreamSink&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to