Title: [289057] trunk/Source/WebCore
Revision
289057
Author
mark....@apple.com
Date
2022-02-03 08:38:40 -0800 (Thu, 03 Feb 2022)

Log Message

Flaky scope.assertNoException() assertion in ~JSExecState when running workers WPT tests
https://bugs.webkit.org/show_bug.cgi?id=235978

Reviewed by Yusuke Suzuki.

Because Web workers can be terminated at any point, it is possible for JSExecState::loadModule()
to get a termination exception, which would incorrectly cause it to assert and crash in debug.
This patch updates the code so that termination exceptions are properly dealt with instead of
crashing.

No new tests, covered by imported/w3c/web-platform-tests/workers that flakily crash in
debug.

* bindings/js/JSDOMExceptionHandling.cpp:
(WebCore::reportException):
* bindings/js/JSExecState.h:
(WebCore::JSExecState::call):
(WebCore::JSExecState::evaluate):
(WebCore::JSExecState::profiledCall):
(WebCore::JSExecState::profiledEvaluate):
(WebCore::JSExecState::linkAndEvaluateModule):
(WebCore::JSExecState::~JSExecState):
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::evaluateInWorld):
* workers/WorkerOrWorkletScriptController.cpp:
(WebCore::WorkerOrWorkletScriptController::loadModuleSynchronously):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (289056 => 289057)


--- trunk/Source/WebCore/ChangeLog	2022-02-03 15:29:18 UTC (rev 289056)
+++ trunk/Source/WebCore/ChangeLog	2022-02-03 16:38:40 UTC (rev 289057)
@@ -1,3 +1,32 @@
+2022-02-03  Mark Lam  <mark....@apple.com>
+
+        Flaky scope.assertNoException() assertion in ~JSExecState when running workers WPT tests
+        https://bugs.webkit.org/show_bug.cgi?id=235978
+
+        Reviewed by Yusuke Suzuki.
+
+        Because Web workers can be terminated at any point, it is possible for JSExecState::loadModule()
+        to get a termination exception, which would incorrectly cause it to assert and crash in debug.
+        This patch updates the code so that termination exceptions are properly dealt with instead of
+        crashing.
+
+        No new tests, covered by imported/w3c/web-platform-tests/workers that flakily crash in
+        debug.
+
+        * bindings/js/JSDOMExceptionHandling.cpp:
+        (WebCore::reportException):
+        * bindings/js/JSExecState.h:
+        (WebCore::JSExecState::call):
+        (WebCore::JSExecState::evaluate):
+        (WebCore::JSExecState::profiledCall):
+        (WebCore::JSExecState::profiledEvaluate):
+        (WebCore::JSExecState::linkAndEvaluateModule):
+        (WebCore::JSExecState::~JSExecState):
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::evaluateInWorld):
+        * workers/WorkerOrWorkletScriptController.cpp:
+        (WebCore::WorkerOrWorkletScriptController::loadModuleSynchronously):
+
 2022-02-03  Chris Dumez  <cdu...@apple.com>
 
         Start connecting SharedWorker to the WebKit2 layer

Modified: trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp (289056 => 289057)


--- trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp	2022-02-03 15:29:18 UTC (rev 289056)
+++ trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp	2022-02-03 16:38:40 UTC (rev 289057)
@@ -91,12 +91,15 @@
 void reportException(JSGlobalObject* lexicalGlobalObject, JSC::Exception* exception, CachedScript* cachedScript, bool fromModule, ExceptionDetails* exceptionDetails)
 {
     VM& vm = lexicalGlobalObject->vm();
-    auto scope = DECLARE_CATCH_SCOPE(vm);
-
     RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
     if (vm.isTerminationException(exception))
         return;
 
+    // We can declare a CatchScope here because we will clear the exception below if it's
+    // not a TerminationException. If it's a TerminationException, it'll remain sticky in
+    // the VM, but we have the check above to ensure that we do not re-enter this scope.
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
     ErrorHandlingScope errorScope(lexicalGlobalObject->vm());
 
     auto callStack = Inspector::createScriptCallStackFromException(lexicalGlobalObject, exception);

Modified: trunk/Source/WebCore/bindings/js/JSExecState.h (289056 => 289057)


--- trunk/Source/WebCore/bindings/js/JSExecState.h	2022-02-03 15:29:18 UTC (rev 289056)
+++ trunk/Source/WebCore/bindings/js/JSExecState.h	2022-02-03 16:38:40 UTC (rev 289057)
@@ -51,14 +51,28 @@
     
     static JSC::JSValue call(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue functionObject, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException)
     {
-        JSExecState currentState(lexicalGlobalObject);
-        return JSC::call(lexicalGlobalObject, functionObject, callData, thisValue, args, returnedException);
+        JSC::VM& vm = JSC::getVM(lexicalGlobalObject);
+        auto scope = DECLARE_CATCH_SCOPE(vm);
+        JSC::JSValue returnValue;
+        {
+            JSExecState currentState(lexicalGlobalObject);
+            returnValue = JSC::call(lexicalGlobalObject, functionObject, callData, thisValue, args, returnedException);
+        }
+        scope.assertNoExceptionExceptTermination();
+        return returnValue;
     }
 
     static JSC::JSValue evaluate(JSC::JSGlobalObject* lexicalGlobalObject, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException)
     {
-        JSExecState currentState(lexicalGlobalObject);
-        return JSC::evaluate(lexicalGlobalObject, source, thisValue, returnedException);
+        JSC::VM& vm = JSC::getVM(lexicalGlobalObject);
+        auto scope = DECLARE_CATCH_SCOPE(vm);
+        JSC::JSValue returnValue;
+        {
+            JSExecState currentState(lexicalGlobalObject);
+            returnValue = JSC::evaluate(lexicalGlobalObject, source, thisValue, returnedException);
+        }
+        scope.assertNoExceptionExceptTermination();
+        return returnValue;
     }
 
     static JSC::JSValue evaluate(JSC::JSGlobalObject* lexicalGlobalObject, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue())
@@ -69,14 +83,28 @@
 
     static JSC::JSValue profiledCall(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ProfilingReason reason, JSC::JSValue functionObject, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException)
     {
-        JSExecState currentState(lexicalGlobalObject);
-        return JSC::profiledCall(lexicalGlobalObject, reason, functionObject, callData, thisValue, args, returnedException);
+        JSC::VM& vm = JSC::getVM(lexicalGlobalObject);
+        auto scope = DECLARE_CATCH_SCOPE(vm);
+        JSC::JSValue returnValue;
+        {
+            JSExecState currentState(lexicalGlobalObject);
+            returnValue = JSC::profiledCall(lexicalGlobalObject, reason, functionObject, callData, thisValue, args, returnedException);
+        }
+        scope.assertNoExceptionExceptTermination();
+        return returnValue;
     }
 
     static JSC::JSValue profiledEvaluate(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException)
     {
-        JSExecState currentState(lexicalGlobalObject);
-        return JSC::profiledEvaluate(lexicalGlobalObject, reason, source, thisValue, returnedException);
+        JSC::VM& vm = JSC::getVM(lexicalGlobalObject);
+        auto scope = DECLARE_CATCH_SCOPE(vm);
+        JSC::JSValue returnValue;
+        {
+            JSExecState currentState(lexicalGlobalObject);
+            returnValue = JSC::profiledEvaluate(lexicalGlobalObject, reason, source, thisValue, returnedException);
+        }
+        scope.assertNoExceptionExceptTermination();
+        return returnValue;
     }
 
     static JSC::JSValue profiledEvaluate(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue())
@@ -107,14 +135,18 @@
     {
         JSC::VM& vm = JSC::getVM(&lexicalGlobalObject);
         auto scope = DECLARE_CATCH_SCOPE(vm);
-    
-        JSExecState currentState(&lexicalGlobalObject);
-        auto returnValue = JSC::linkAndEvaluateModule(&lexicalGlobalObject, moduleKey, scriptFetcher);
-        if (UNLIKELY(scope.exception())) {
-            returnedException = scope.exception();
-            scope.clearException();
-            return JSC::jsUndefined();
+        JSC::JSValue returnValue;
+        {
+            JSExecState currentState(&lexicalGlobalObject);
+            returnValue = JSC::linkAndEvaluateModule(&lexicalGlobalObject, moduleKey, scriptFetcher);
+            if (UNLIKELY(scope.exception())) {
+                returnedException = scope.exception();
+                if (!vm.hasPendingTerminationException())
+                    scope.clearException();
+                return JSC::jsUndefined();
+            }
         }
+        scope.assertNoExceptionExceptTermination();
         return returnValue;
     }
 
@@ -131,8 +163,8 @@
     ~JSExecState()
     {
         JSC::VM& vm = currentState()->vm();
-        auto scope = DECLARE_CATCH_SCOPE(vm);
-        scope.assertNoException();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+        scope.assertNoExceptionExceptTermination();
 
         JSC::JSGlobalObject* lexicalGlobalObject = currentState();
         bool didExitJavaScript = lexicalGlobalObject && !m_previousState;
@@ -142,7 +174,8 @@
         if (didExitJavaScript) {
             didLeaveScriptContext(lexicalGlobalObject);
             // We need to clear any exceptions from microtask drain.
-            scope.clearException();
+            if (!vm.hasPendingTerminationException())
+                scope.clearException();
         }
     }
 

Modified: trunk/Source/WebCore/bindings/js/ScriptController.cpp (289056 => 289057)


--- trunk/Source/WebCore/bindings/js/ScriptController.cpp	2022-02-03 15:29:18 UTC (rev 289056)
+++ trunk/Source/WebCore/bindings/js/ScriptController.cpp	2022-02-03 16:38:40 UTC (rev 289057)
@@ -120,8 +120,14 @@
 
 ValueOrException ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world)
 {
-    JSLockHolder lock(world.vm());
+    auto& vm = world.vm();
+    JSLockHolder lock(vm);
 
+    if (vm.hasPendingTerminationException()) {
+        ExceptionDetails details;
+        return makeUnexpected(details);
+    }
+
     const SourceCode& jsSourceCode = sourceCode.jsSourceCode();
     const URL& sourceURL = jsSourceCode.provider()->sourceOrigin().url();
 

Modified: trunk/Source/WebCore/workers/WorkerOrWorkletScriptController.cpp (289056 => 289057)


--- trunk/Source/WebCore/workers/WorkerOrWorkletScriptController.cpp	2022-02-03 15:29:18 UTC (rev 289056)
+++ trunk/Source/WebCore/workers/WorkerOrWorkletScriptController.cpp	2022-02-03 16:38:40 UTC (rev 289057)
@@ -280,10 +280,13 @@
     auto& globalObject = *m_globalScopeWrapper.get();
     VM& vm = globalObject.vm();
     JSLockHolder lock { vm };
+    auto scope = DECLARE_THROW_SCOPE(vm);
 
     Ref protector { scriptFetcher };
     {
         auto& promise = JSExecState::loadModule(globalObject, sourceCode.jsSourceCode(), JSC::JSScriptFetcher::create(vm, { &scriptFetcher }));
+        scope.assertNoExceptionExceptTermination();
+        RETURN_IF_EXCEPTION(scope, false);
 
         auto& fulfillHandler = *JSNativeStdFunction::create(vm, &globalObject, 1, String(), [protector](JSGlobalObject* globalObject, CallFrame* callFrame) -> JSC::EncodedJSValue {
             VM& vm = globalObject->vm();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to