From 301a1fc7631bb862f003cc2ebfab37a42e5fdbc5 Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Thu, 11 Apr 2024 00:25:54 +0200 Subject: [PATCH] LibJS: Propagate finalizers into nested try-catch blocks without them --- .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 9 +++- Userland/Libraries/LibJS/Bytecode/Generator.h | 2 + .../LibJS/Tests/try-catch-finally-nested.js | 50 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 476dbbc07bb..cd997b3be15 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2510,8 +2510,13 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener if (m_finalizer) generator.end_boundary(Bytecode::Generator::BlockBoundaryType::ReturnToFinally); if (m_handler) { - if (!m_finalizer) - unwind_context.emplace(generator, OptionalNone()); + if (!m_finalizer) { + auto const* parent_unwind_context = generator.current_unwind_context(); + if (parent_unwind_context) + unwind_context.emplace(generator, parent_unwind_context->finalizer()); + else + unwind_context.emplace(generator, OptionalNone()); + } unwind_context->set_handler(handler_target.value()); } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 1b9b81ae69c..b1968961c14 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -276,6 +276,8 @@ public: return Operand(Operand::Type::Constant, m_constants.size() - 1); } + UnwindContext const* current_unwind_context() const { return m_current_unwind_context; } + private: VM& m_vm; diff --git a/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js b/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js index da9ad2d438a..7614b054838 100644 --- a/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js +++ b/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js @@ -53,3 +53,53 @@ test("Nested try/catch/finally with exceptions", () => { expect(level3CatchHasBeenExecuted).toBeTrue(); expect(level3FinallyHasBeenExecuted).toBeTrue(); }); + +test("Nested try/catch/finally with return in inner context", () => { + success = false; + (() => { + try { + try { + return; + } catch (e) { + expect().fail(); + } + } finally { + success = true; + } + expect().fail(); + })(); + expect(success).toBeTrue(); +}); + +test("Deeply nested try/catch/finally with return in inner context", () => { + success = 0; + (() => { + try { + try { + try { + try { + try { + return; + } catch (e) { + expect().fail(); + } finally { + success += 4; + } + } catch (e) { + expect().fail(); + } + } catch (e) { + expect().fail(); + } finally { + success += 2; + } + } catch (e) { + expect().fail(); + } + } finally { + success += 1; + } + expect().fail(); + })(); + expect(success).toBe(7); +});