summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/CyclicModule.cpp
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-11-26 13:37:06 +0100
committerLinus Groh <mail@linusgroh.de>2022-11-27 00:51:36 +0000
commit1dc9769f7ddb5395b03e603c960da1bde862a89a (patch)
tree13dc184ac301b3cb331fb69ce268485761772bbe /Userland/Libraries/LibJS/CyclicModule.cpp
parentd87676de8a8cafb029e3eff7c5867f579c2d25ea (diff)
downloadserenity-1dc9769f7ddb5395b03e603c960da1bde862a89a.zip
LibJS: No longer assume there is a cycle root when module failed before
This issue could be triggered by evaluating a module twice. If it failed during evaluation the cycle root was never set but that status is evaluated. This failed in step 3 of Evaluate which assumes it has a cycle root. This is a spec issue see: https://github.com/tc39/ecma262/issues/2823 To fix this we check if the module itself has a top level capability first before going to the cycle root. Co-authored-by: Jamie Mansfield <jmansfield@cadixdev.org>
Diffstat (limited to 'Userland/Libraries/LibJS/CyclicModule.cpp')
-rw-r--r--Userland/Libraries/LibJS/CyclicModule.cpp11
1 files changed, 10 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/CyclicModule.cpp b/Userland/Libraries/LibJS/CyclicModule.cpp
index 835250e0f0..361e0233e5 100644
--- a/Userland/Libraries/LibJS/CyclicModule.cpp
+++ b/Userland/Libraries/LibJS/CyclicModule.cpp
@@ -191,10 +191,19 @@ ThrowCompletionOr<Promise*> CyclicModule::evaluate(VM& vm)
// 2. Assert: module.[[Status]] is linked, evaluating-async, or evaluated.
VERIFY(m_status == ModuleStatus::Linked || m_status == ModuleStatus::EvaluatingAsync || m_status == ModuleStatus::Evaluated);
+ // NOTE: The spec does not catch the case where evaluate is called twice on a script which failed
+ // during evaluation. This means the script is evaluated but does not have a cycle root.
+ // In that case we first check if this module itself has a top level capability.
+ // See also: https://github.com/tc39/ecma262/issues/2823 .
+ if (m_top_level_capability != nullptr)
+ return verify_cast<Promise>(m_top_level_capability->promise().ptr());
+
// 3. If module.[[Status]] is evaluating-async or evaluated, set module to module.[[CycleRoot]].
if (m_status == ModuleStatus::EvaluatingAsync || m_status == ModuleStatus::Evaluated) {
// Note: This will continue this function with module.[[CycleRoot]]
- VERIFY(m_cycle_root && m_cycle_root->m_status == ModuleStatus::Linked && this != m_cycle_root);
+ VERIFY(m_cycle_root);
+ VERIFY(this != m_cycle_root);
+ VERIFY(m_cycle_root->m_status == ModuleStatus::Linked);
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] evaluate[{}](vm) deferring to cycle root at {}", this, m_cycle_root);
return m_cycle_root->evaluate(vm);
}