From 1dc9769f7ddb5395b03e603c960da1bde862a89a Mon Sep 17 00:00:00 2001 From: davidot Date: Sat, 26 Nov 2022 13:37:06 +0100 Subject: [PATCH] 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 --- Userland/Libraries/LibJS/CyclicModule.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/CyclicModule.cpp b/Userland/Libraries/LibJS/CyclicModule.cpp index 835250e0f0e..361e0233e5d 100644 --- a/Userland/Libraries/LibJS/CyclicModule.cpp +++ b/Userland/Libraries/LibJS/CyclicModule.cpp @@ -191,10 +191,19 @@ ThrowCompletionOr 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(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); }