LibJS: Stop swallowing exceptions in finalizers

This also fixes one of the try-catch-finally tests, and adds a new one.
This commit is contained in:
Hendiadyoin1 2024-04-11 11:12:21 +02:00 committed by Andreas Kling
commit 27b238d9af
Notes: sideshowbarker 2024-07-17 04:01:41 +09:00
3 changed files with 30 additions and 16 deletions

View file

@ -410,11 +410,6 @@ void Interpreter::run_bytecode()
} }
if (finalizer) { if (finalizer) {
m_current_block = finalizer; m_current_block = finalizer;
// If an exception was thrown inside the corresponding `catch` block, we need to rethrow it
// from the `finally` block. But if the exception is from the `try` block, and has already been
// handled by `catch`, we swallow it.
if (!unwind_context.handler_called)
reg(Register::exception()) = {};
goto start; goto start;
} }
// An unwind context with no handler or finalizer? We have nowhere to jump, and continuing on will make us crash on the next `Call` to a non-native function if there's an exception! So let's crash here instead. // An unwind context with no handler or finalizer? We have nowhere to jump, and continuing on will make us crash on the next `Call` to a non-native function if there's an exception! So let's crash here instead.

View file

@ -103,3 +103,18 @@ test("Deeply nested try/catch/finally with return in inner context", () => {
})(); })();
expect(success).toBe(7); expect(success).toBe(7);
}); });
test("Nested try/finally/catch with exception in inner context ", () => {
success = 0;
try {
try {
throw Error("Error in inner try");
} finally {
success += 1;
}
expect.fail();
} catch (e) {
success += 1;
}
expect(success).toBe(2);
});

View file

@ -342,6 +342,7 @@ test("labelled break in finally overrides labelled break in try", () => {
test("Throw while breaking", () => { test("Throw while breaking", () => {
const executionOrder = []; const executionOrder = [];
expect(() => {
try { try {
for (const i = 1337; ; expect().fail("Jumped to for loop update block")) { for (const i = 1337; ; expect().fail("Jumped to for loop update block")) {
try { try {
@ -349,12 +350,15 @@ test("Throw while breaking", () => {
break; break;
} finally { } finally {
executionOrder.push(2); executionOrder.push(2);
throw 1; throw Error(1);
} }
} }
} finally { } finally {
executionOrder.push(3); executionOrder.push(3);
} }
expect().fail("Running code after for loop");
}).toThrowWithMessage(Error, 1);
expect(() => { expect(() => {
i; i;
}).toThrowWithMessage(ReferenceError, "'i' is not defined"); }).toThrowWithMessage(ReferenceError, "'i' is not defined");