Commit 843341ce authored by Hiroshige Hayashizaki's avatar Hiroshige Hayashizaki Committed by Commit Bot

Consider module script evaluation with an exception as a failure

Previously, when an exception is thrown,
ModulatorImplBase::ExecuteModule() returns
ModuleEvaluationResult::Empty(),
when CaptureEvalErrorFlag::kReport is used and
top-level await is not enabled.
This is considered as success, but this is inconsistent with

- ModuleRecord::Evaluate() that returns
  ModuleEvaluationResult::FromException()
  (that is considered as non-success), and
- Classic script evaluation.

This CL makes ModulatorImplBase::ExecuteModule() return
ModuleEvaluationResult with an exception in such cases.

Behavior change:
This changes WorkerReportingProxy::DidEvaluateTopLevelScript()'s
|is_success| value from true to false when a module script
have parse/evaluation/etc. errors.
This makes serviceworker registration fails for such scripts,
fixing crbug.com/1129795.

This CL fixes content/test/data/service_worker/worker.js
to use `globalThis` instead of `this`, because on module scripts
`this` can't be used to get the global object.
(Previously, the test using this script
ServiceWorkerVersionBrowserTest.StartInstalledModuleScriptWhileOffline
unexpectedly threw an exception during evaluation of `worker.js`
as a module service worker top-level script, but didn't fail
due to this issue)

Bug: 1129795, 1129743, 1111134
Change-Id: I5443539c201e1ab220fd17f9291b307432853450
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419054
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarDominic Farolino <dom@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810141}
parent c1a7d15a
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
this.oninstall = function(event) {}; globalThis.oninstall = function(event) {};
// So sorry about this waste of bytes: // So sorry about this waste of bytes:
// Filler comment, to trigger code caching heuristic (script > 1K.) // Filler comment, to trigger code caching heuristic (script > 1K.)
......
...@@ -203,10 +203,11 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>, ...@@ -203,10 +203,11 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
// - When "rethrow errors" is to be set, use kCapture for EvaluateModule(). // - When "rethrow errors" is to be set, use kCapture for EvaluateModule().
// Then EvaluateModule() wraps exceptions in a ModuleEvaluationResult instead // Then EvaluateModule() wraps exceptions in a ModuleEvaluationResult instead
// of throwing it and the caller should rethrow the exception. // of throwing it and the caller should rethrow the exception.
// - When "rethrow errors" is not to be set, use kReport. EvaluateModule() // - When "rethrow errors" is not to be set, use kReport. If there is an error
// "report the error" inside it (if any), and returns either a // to throw, EvaluateModule() "report the error" inside it, and returns
// ModuleEvaluationResult that is empty or contains the successful // ModuleEvaluationResult wrapping the error. Otherwise, it returns either a
// evaluation result. // ModuleEvaluationResult that is empty or contains the successful evaluation
// result.
virtual ModuleEvaluationResult ExecuteModule(ModuleScript*, virtual ModuleEvaluationResult ExecuteModule(ModuleScript*,
CaptureEvalErrorFlag) = 0; CaptureEvalErrorFlag) = 0;
......
...@@ -336,6 +336,7 @@ void ModulatorImplBase::ProduceCacheModuleTree( ...@@ -336,6 +336,7 @@ void ModulatorImplBase::ProduceCacheModuleTree(
} }
// <specdef href="https://html.spec.whatwg.org/C/#run-a-module-script"> // <specdef href="https://html.spec.whatwg.org/C/#run-a-module-script">
// Spec with TLA: https://github.com/whatwg/html/pull/4352
ModuleEvaluationResult ModulatorImplBase::ExecuteModule( ModuleEvaluationResult ModulatorImplBase::ExecuteModule(
ModuleScript* module_script, ModuleScript* module_script,
CaptureEvalErrorFlag capture_error) { CaptureEvalErrorFlag capture_error) {
...@@ -409,24 +410,23 @@ ModuleEvaluationResult ModulatorImplBase::ExecuteModule( ...@@ -409,24 +410,23 @@ ModuleEvaluationResult ModulatorImplBase::ExecuteModule(
result.GetPromise(script_state_) result.GetPromise(script_state_)
.Then(v8::Local<v8::Function>(), callback_failure); .Then(v8::Local<v8::Function>(), callback_failure);
} }
return result.Escape(&scope);
} else { } else {
// <spec step="8">If evaluationStatus is an abrupt completion, then:</spec> // <spec step="8">If evaluationStatus is an abrupt completion, then:</spec>
if (result.IsException()) { if (result.IsException()) {
// <spec step="8.1">If rethrow errors is true, rethrow the exception given // <spec step="8.1">If rethrow errors is true, rethrow the exception given
// by evaluationStatus.[[Value]].</spec> // by evaluationStatus.[[Value]].</spec>
if (capture_error == CaptureEvalErrorFlag::kCapture) if (capture_error == CaptureEvalErrorFlag::kReport) {
return result.Escape(&scope);
// <spec step="8.2">Otherwise, report the exception given by // <spec step="8.2">Otherwise, report the exception given by
// evaluationStatus.[[Value]] for script.</spec> // evaluationStatus.[[Value]] for script.</spec>
ModuleRecord::ReportException(script_state_, result.GetException()); ModuleRecord::ReportException(script_state_, result.GetException());
} }
}
}
// <spec step="8">Clean up after running script with settings.</spec> // <spec step="8">Clean up after running script with settings.</spec>
// - Partially implement in MicrotaskScope destructor and the // - Partially implement in MicrotaskScope destructor and the
// - ScriptState::EscapableScope destructor. // - ScriptState::EscapableScope destructor.
return ModuleEvaluationResult::Empty(); return result.Escape(&scope);
}
} }
void ModulatorImplBase::Trace(Visitor* visitor) const { void ModulatorImplBase::Trace(Visitor* visitor) const {
......
This is a testharness.js-based test.
PASS Registering invalid chunked encoding script
PASS Registering invalid chunked encoding script with flush
FAIL Registering script including parse error assert_unreached: Should have rejected: Registration of script including parse error should fail. Reached unreachable code
FAIL Registering script including undefined error assert_unreached: Should have rejected: Registration of script including undefined error should fail. Reached unreachable code
FAIL Registering script including uncaught exception assert_unreached: Should have rejected: Registration of script including uncaught exception should fail. Reached unreachable code
PASS Registering non-existent script
PASS Registering script including caught exception
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment