From 65420677982107ad0561b42ea8072069ff79f812 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:52:46 +0000 Subject: [PATCH 1/5] inspector: bump WebKit so Console.enable replay survives validateExceptionChecks jsToInspectorValue calls getOwnPropertyNames then object.get() with no exception check between them. InspectorConsoleAgent::enable()'s replay of buffered console messages runs from backend dispatch with no JS frame on the stack, so the inner ThrowScope destructor in getOwnNonIndexPropertyNames simulates a throw and the next ThrowScope constructor in JSObject::get sees it unchecked. The live addConsoleMessage path has a topEntryFrame and skips the simulated throw. oven-sh/WebKit#376 adds a ThrowScope with RETURN_IF_EXCEPTION to the object branch of jsToInspectorValue and a TopExceptionScope to toInspectorValue. This bumps WEBKIT_VERSION to that PR's preview build and adds a test that connects to --inspect-wait with validateExceptionChecks=1, lets two console.log calls buffer, then sends Console.enable and asserts the buffered messages are replayed without aborting. A lint test in webkit-prebuilt-url.test.ts fails while WEBKIT_VERSION is a preview tag so this cannot merge until oven-sh/WebKit#376 is merged and the pin swapped to the resulting main sha. --- scripts/build/deps/webkit.ts | 4 +- test/cli/inspect/inspect.test.ts | 113 +++++++++++++++++- .../source-lints/webkit-prebuilt-url.test.ts | 7 ++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/scripts/build/deps/webkit.ts b/scripts/build/deps/webkit.ts index 45502005f29a..6128509013fb 100644 --- a/scripts/build/deps/webkit.ts +++ b/scripts/build/deps/webkit.ts @@ -3,7 +3,9 @@ * for local mode. Override via `--webkit-version=` to test a branch. * From https://github.com/oven-sh/WebKit releases. */ -export const WEBKIT_VERSION = "34c01d13391e00c06862a3d2c5b7fff350ac87e0"; +// Preview of oven-sh/WebKit#376: exception checks in jsToInspectorValue so +// Console.enable replay of buffered messages survives validateExceptionChecks=1. +export const WEBKIT_VERSION = "autobuild-preview-pr-376-e68eb1fd"; /** * WebKit (JavaScriptCore) — the JS engine. diff --git a/test/cli/inspect/inspect.test.ts b/test/cli/inspect/inspect.test.ts index 04719466ad3e..26f00e5863bf 100644 --- a/test/cli/inspect/inspect.test.ts +++ b/test/cli/inspect/inspect.test.ts @@ -1,7 +1,7 @@ import { Subprocess, spawn } from "bun"; import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test"; import fs from "fs"; -import { bunEnv, bunExe, isPosix, randomPort, tempDir } from "harness"; +import { bunEnv, bunExe, isASAN, isDebug, isPosix, randomPort, tempDir } from "harness"; import { join } from "node:path"; import stripAnsi from "strip-ansi"; import { WebSocket } from "ws"; @@ -300,6 +300,117 @@ describe("websocket", () => { }); }); +// jsToInspectorValue (InjectedScriptBase.cpp) called getOwnPropertyNames and then object.get() +// on each property with no exception check between them. The live console.log path has a JS +// topEntryFrame on the stack so the inner ThrowScope destructor skips the simulated throw, but +// InspectorConsoleAgent::enable()'s replay of buffered messages runs from backend dispatch with +// no JS frame, so validation trips: "getOwnNonIndexPropertyNames ... unchecked as of get". +// ENABLE_EXCEPTION_SCOPE_VERIFICATION is (ASSERT_ENABLED || ASAN_ENABLED), so this only runs on +// debug / asan builds. +test.skipIf(!isDebug && !isASAN)( + "Console.enable replay of buffered messages does not trip exception-check validation", + async () => { + await using child = spawn({ + cmd: [ + bunExe(), + "--inspect-wait=127.0.0.1:0", + "-e", + `console.log("BUFFER-A"); console.log("BUFFER-B"); setInterval(()=>{},1000);`, + ], + env: { + ...bunEnv, + BUN_JSC_validateExceptionChecks: "1", + BUN_JSC_dumpSimulatedThrows: "1", + }, + stdout: "pipe", + stderr: "pipe", + }); + + let stderr = ""; + let stdout = ""; + const decoder = new TextDecoder(); + const { promise: urlPromise, resolve: resolveUrl, reject: rejectUrl } = Promise.withResolvers(); + const stderrDrained = (async () => { + for await (const chunk of child.stderr) { + stderr += decoder.decode(chunk); + const m = stderr.match(/ws:\/\/[^\s]+/); + if (m) resolveUrl(new URL(m[0])); + } + rejectUrl(new Error("inspectee exited before printing inspector URL:\n" + stderr)); + })(); + const { promise: bufferedPromise, resolve: resolveBuffered } = Promise.withResolvers(); + const stdoutDrained = (async () => { + for await (const chunk of child.stdout) { + stdout += decoder.decode(chunk); + if (stdout.includes("BUFFER-A") && stdout.includes("BUFFER-B")) resolveBuffered(); + } + })(); + + const url = await urlPromise; + const ws = new WebSocket(url); + const replayed: string[] = []; + let reply: unknown; + try { + let nextId = 1; + let failed: unknown; + const pending = new Map void>(); + const send = (method: string, params: object = {}) => + new Promise(resolve => { + if (failed) return resolve(failed); + const id = nextId++; + pending.set(id, resolve); + ws.send(JSON.stringify({ id, method, params })); + }); + const fail = (r: unknown) => { + failed ??= r; + for (const p of pending.values()) p(r); + pending.clear(); + }; + ws.addEventListener("message", ev => { + const msg = JSON.parse(String(ev.data)); + if (msg.id && pending.has(msg.id)) { + pending.get(msg.id)!(msg); + pending.delete(msg.id); + } else if (msg.method === "Console.messageAdded") { + replayed.push(msg.params.message.text); + } + }); + ws.addEventListener("close", ({ code, reason }) => fail({ closed: { code, reason } })); + ws.addEventListener("error", cause => fail({ error: String(cause) })); + await new Promise((resolve, reject) => { + ws.addEventListener("open", () => resolve()); + ws.addEventListener("error", cause => reject(new Error("WebSocket error", { cause }))); + }); + + // Let user code run and buffer the two console.log calls in InspectorConsoleAgent, + // then send Console.enable so enable() replays them with no JS on the stack. + await send("Inspector.enable"); + await send("Inspector.initialized"); + await Promise.race([bufferedPromise, child.exited]); + // enable() dispatches the buffered Console.messageAdded events synchronously before + // replying, so once this resolves the replayed[] array is complete. A second round-trip + // guards against any cross-thread delivery reordering. + reply = await send("Console.enable"); + await send("Runtime.evaluate", { expression: "1" }); + } finally { + ws.close(); + child.kill(); + } + + await Promise.all([child.exited, stderrDrained.catch(() => {}), stdoutDrained]); + // Without the WebKit-side fix the inspectee SIGABRTs ("Unchecked JS exception: + // getOwnNonIndexPropertyNames ... unchecked as of get") inside toInspectorValue before + // replying to Console.enable, so the socket closes 1006 and reply is { closed: ... }. + if (child.signalCode === "SIGABRT") { + throw new Error( + `inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`, + ); + } + expect(reply).toMatchObject({ id: expect.any(Number), result: {} }); + expect(replayed).toEqual(expect.arrayContaining(["BUFFER-A", "BUFFER-B"])); + }, +); + describe("http metadata endpoint", () => { let metadataInspectee: Subprocess | undefined; diff --git a/test/internal/source-lints/webkit-prebuilt-url.test.ts b/test/internal/source-lints/webkit-prebuilt-url.test.ts index 5a7ac2701e94..992518362ef1 100644 --- a/test/internal/source-lints/webkit-prebuilt-url.test.ts +++ b/test/internal/source-lints/webkit-prebuilt-url.test.ts @@ -123,4 +123,11 @@ describe("WebKit prebuilt URL", () => { test("WEBKIT_VERSION is either a 40-hex sha or an autobuild-* tag", () => { expect(/^[0-9a-f]{40}$/.test(WEBKIT_VERSION) || WEBKIT_VERSION.startsWith("autobuild-")).toBe(true); }); + + // autobuild-preview-pr-* releases are deleted when the oven-sh/WebKit PR + // merges or closes, which would 404 every fresh build of main. Preview pins + // are fine on a branch while iterating; this test is the merge gate. + test("WEBKIT_VERSION is not an autobuild-preview-* tag (preview releases are deleted on upstream merge)", () => { + expect(WEBKIT_VERSION.startsWith("autobuild-preview-")).toBe(false); + }); }); From d850ecaea84f39d148e72ffc7e4297b4add2aad5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:56:15 +0000 Subject: [PATCH 2/5] [autofix.ci] apply automated fixes --- test/cli/inspect/inspect.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/cli/inspect/inspect.test.ts b/test/cli/inspect/inspect.test.ts index 26f00e5863bf..df269cb8f253 100644 --- a/test/cli/inspect/inspect.test.ts +++ b/test/cli/inspect/inspect.test.ts @@ -402,9 +402,7 @@ test.skipIf(!isDebug && !isASAN)( // getOwnNonIndexPropertyNames ... unchecked as of get") inside toInspectorValue before // replying to Console.enable, so the socket closes 1006 and reply is { closed: ... }. if (child.signalCode === "SIGABRT") { - throw new Error( - `inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`, - ); + throw new Error(`inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`); } expect(reply).toMatchObject({ id: expect.any(Number), result: {} }); expect(replayed).toEqual(expect.arrayContaining(["BUFFER-A", "BUFFER-B"])); From 3cc6bb613c040ef3607f9e5456243a471c129db7 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:32:34 +0000 Subject: [PATCH 3/5] reword preview-pin merge gate: previews aren't deleted, they're just not on WebKit main --- test/internal/source-lints/webkit-prebuilt-url.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/internal/source-lints/webkit-prebuilt-url.test.ts b/test/internal/source-lints/webkit-prebuilt-url.test.ts index 992518362ef1..3272c456e7a1 100644 --- a/test/internal/source-lints/webkit-prebuilt-url.test.ts +++ b/test/internal/source-lints/webkit-prebuilt-url.test.ts @@ -124,10 +124,11 @@ describe("WebKit prebuilt URL", () => { expect(/^[0-9a-f]{40}$/.test(WEBKIT_VERSION) || WEBKIT_VERSION.startsWith("autobuild-")).toBe(true); }); - // autobuild-preview-pr-* releases are deleted when the oven-sh/WebKit PR - // merges or closes, which would 404 every fresh build of main. Preview pins + // autobuild-preview-pr-* tags point at PR-branch commits that are not on + // oven-sh/WebKit main and are pre-releases with no retention guarantee; main + // must pin a 40-hex sha from a merged autobuild- release. Preview pins // are fine on a branch while iterating; this test is the merge gate. - test("WEBKIT_VERSION is not an autobuild-preview-* tag (preview releases are deleted on upstream merge)", () => { + test("WEBKIT_VERSION is not an autobuild-preview-* tag (main must pin a merged autobuild- release)", () => { expect(WEBKIT_VERSION.startsWith("autobuild-preview-")).toBe(false); }); }); From 6c992dbf7b1422560a2be3fc5791b5b8707df791 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 30 Jul 2026 16:05:25 +0000 Subject: [PATCH 4/5] move Console.enable validation test to its own file inspect.test.ts has pre-existing localhost-vs-[::1] failures in the gate environment and is ASAN-quarantined in CI, so the new test never ran there. Drop the preview-pin lint (the preview pin is called out in the PR body and in the webkit.ts comment; the PR will swap to the main sha once oven-sh/WebKit#376 merges). --- .../inspect/inspect-exception-checks.test.ts | 114 ++++++++++++++++++ test/cli/inspect/inspect.test.ts | 111 +---------------- .../source-lints/webkit-prebuilt-url.test.ts | 8 -- test/no-validate-leaksan.txt | 1 + 4 files changed, 116 insertions(+), 118 deletions(-) create mode 100644 test/cli/inspect/inspect-exception-checks.test.ts diff --git a/test/cli/inspect/inspect-exception-checks.test.ts b/test/cli/inspect/inspect-exception-checks.test.ts new file mode 100644 index 000000000000..25c921706440 --- /dev/null +++ b/test/cli/inspect/inspect-exception-checks.test.ts @@ -0,0 +1,114 @@ +import { spawn } from "bun"; +import { expect, test } from "bun:test"; +import { bunEnv, bunExe, isASAN, isDebug } from "harness"; + +// jsToInspectorValue (InjectedScriptBase.cpp) called getOwnPropertyNames and then object.get() +// on each property with no exception check between them. The live console.log path has a JS +// topEntryFrame on the stack so the inner ThrowScope destructor skips the simulated throw, but +// InspectorConsoleAgent::enable()'s replay of buffered messages runs from backend dispatch with +// no JS frame, so validation trips: "getOwnNonIndexPropertyNames ... unchecked as of get". +// ENABLE_EXCEPTION_SCOPE_VERIFICATION is (ASSERT_ENABLED || ASAN_ENABLED), so this only runs on +// debug / asan builds. +test.skipIf(!isDebug && !isASAN)( + "Console.enable replay of buffered messages does not trip exception-check validation", + async () => { + await using child = spawn({ + cmd: [ + bunExe(), + "--inspect-wait=127.0.0.1:0", + "-e", + `console.log("BUFFER-A"); console.log("BUFFER-B"); setInterval(()=>{},1000);`, + ], + env: { + ...bunEnv, + BUN_JSC_validateExceptionChecks: "1", + BUN_JSC_dumpSimulatedThrows: "1", + }, + stdout: "pipe", + stderr: "pipe", + }); + + let stderr = ""; + let stdout = ""; + const decoder = new TextDecoder(); + const { promise: urlPromise, resolve: resolveUrl, reject: rejectUrl } = Promise.withResolvers(); + const stderrDrained = (async () => { + for await (const chunk of child.stderr) { + stderr += decoder.decode(chunk); + const m = stderr.match(/ws:\/\/[^\s]+/); + if (m) resolveUrl(new URL(m[0])); + } + rejectUrl(new Error("inspectee exited before printing inspector URL:\n" + stderr)); + })(); + const { promise: bufferedPromise, resolve: resolveBuffered } = Promise.withResolvers(); + const stdoutDrained = (async () => { + for await (const chunk of child.stdout) { + stdout += decoder.decode(chunk); + if (stdout.includes("BUFFER-A") && stdout.includes("BUFFER-B")) resolveBuffered(); + } + })(); + + const url = await urlPromise; + const ws = new WebSocket(url); + const replayed: string[] = []; + let reply: unknown; + try { + let nextId = 1; + let failed: unknown; + const pending = new Map void>(); + const send = (method: string, params: object = {}) => + new Promise(resolve => { + if (failed) return resolve(failed); + const id = nextId++; + pending.set(id, resolve); + ws.send(JSON.stringify({ id, method, params })); + }); + const fail = (r: unknown) => { + failed ??= r; + for (const p of pending.values()) p(r); + pending.clear(); + }; + ws.addEventListener("message", ev => { + const msg = JSON.parse(String(ev.data)); + if (msg.id && pending.has(msg.id)) { + pending.get(msg.id)!(msg); + pending.delete(msg.id); + } else if (msg.method === "Console.messageAdded") { + replayed.push(msg.params.message.text); + } + }); + ws.addEventListener("close", ({ code, reason }) => fail({ closed: { code, reason } })); + ws.addEventListener("error", cause => fail({ error: String(cause) })); + await new Promise((resolve, reject) => { + ws.addEventListener("open", () => resolve()); + ws.addEventListener("error", cause => reject(new Error("WebSocket error", { cause }))); + }); + + // Let user code run and buffer the two console.log calls in InspectorConsoleAgent, + // then send Console.enable so enable() replays them with no JS on the stack. + await send("Inspector.enable"); + await send("Inspector.initialized"); + await Promise.race([bufferedPromise, child.exited]); + // enable() dispatches the buffered Console.messageAdded events synchronously before + // replying, so once this resolves the replayed[] array is complete. A second round-trip + // guards against any cross-thread delivery reordering. + reply = await send("Console.enable"); + await send("Runtime.evaluate", { expression: "1" }); + } finally { + ws.close(); + child.kill(); + } + + await Promise.all([child.exited, stderrDrained.catch(() => {}), stdoutDrained]); + // Without the WebKit-side fix the inspectee SIGABRTs ("Unchecked JS exception: + // getOwnNonIndexPropertyNames ... unchecked as of get") inside toInspectorValue before + // replying to Console.enable, so the socket closes 1006 and reply is { closed: ... }. + if (child.signalCode === "SIGABRT") { + throw new Error( + `inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`, + ); + } + expect(reply).toMatchObject({ id: expect.any(Number), result: {} }); + expect(replayed).toEqual(expect.arrayContaining(["BUFFER-A", "BUFFER-B"])); + }, +); diff --git a/test/cli/inspect/inspect.test.ts b/test/cli/inspect/inspect.test.ts index df269cb8f253..04719466ad3e 100644 --- a/test/cli/inspect/inspect.test.ts +++ b/test/cli/inspect/inspect.test.ts @@ -1,7 +1,7 @@ import { Subprocess, spawn } from "bun"; import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test"; import fs from "fs"; -import { bunEnv, bunExe, isASAN, isDebug, isPosix, randomPort, tempDir } from "harness"; +import { bunEnv, bunExe, isPosix, randomPort, tempDir } from "harness"; import { join } from "node:path"; import stripAnsi from "strip-ansi"; import { WebSocket } from "ws"; @@ -300,115 +300,6 @@ describe("websocket", () => { }); }); -// jsToInspectorValue (InjectedScriptBase.cpp) called getOwnPropertyNames and then object.get() -// on each property with no exception check between them. The live console.log path has a JS -// topEntryFrame on the stack so the inner ThrowScope destructor skips the simulated throw, but -// InspectorConsoleAgent::enable()'s replay of buffered messages runs from backend dispatch with -// no JS frame, so validation trips: "getOwnNonIndexPropertyNames ... unchecked as of get". -// ENABLE_EXCEPTION_SCOPE_VERIFICATION is (ASSERT_ENABLED || ASAN_ENABLED), so this only runs on -// debug / asan builds. -test.skipIf(!isDebug && !isASAN)( - "Console.enable replay of buffered messages does not trip exception-check validation", - async () => { - await using child = spawn({ - cmd: [ - bunExe(), - "--inspect-wait=127.0.0.1:0", - "-e", - `console.log("BUFFER-A"); console.log("BUFFER-B"); setInterval(()=>{},1000);`, - ], - env: { - ...bunEnv, - BUN_JSC_validateExceptionChecks: "1", - BUN_JSC_dumpSimulatedThrows: "1", - }, - stdout: "pipe", - stderr: "pipe", - }); - - let stderr = ""; - let stdout = ""; - const decoder = new TextDecoder(); - const { promise: urlPromise, resolve: resolveUrl, reject: rejectUrl } = Promise.withResolvers(); - const stderrDrained = (async () => { - for await (const chunk of child.stderr) { - stderr += decoder.decode(chunk); - const m = stderr.match(/ws:\/\/[^\s]+/); - if (m) resolveUrl(new URL(m[0])); - } - rejectUrl(new Error("inspectee exited before printing inspector URL:\n" + stderr)); - })(); - const { promise: bufferedPromise, resolve: resolveBuffered } = Promise.withResolvers(); - const stdoutDrained = (async () => { - for await (const chunk of child.stdout) { - stdout += decoder.decode(chunk); - if (stdout.includes("BUFFER-A") && stdout.includes("BUFFER-B")) resolveBuffered(); - } - })(); - - const url = await urlPromise; - const ws = new WebSocket(url); - const replayed: string[] = []; - let reply: unknown; - try { - let nextId = 1; - let failed: unknown; - const pending = new Map void>(); - const send = (method: string, params: object = {}) => - new Promise(resolve => { - if (failed) return resolve(failed); - const id = nextId++; - pending.set(id, resolve); - ws.send(JSON.stringify({ id, method, params })); - }); - const fail = (r: unknown) => { - failed ??= r; - for (const p of pending.values()) p(r); - pending.clear(); - }; - ws.addEventListener("message", ev => { - const msg = JSON.parse(String(ev.data)); - if (msg.id && pending.has(msg.id)) { - pending.get(msg.id)!(msg); - pending.delete(msg.id); - } else if (msg.method === "Console.messageAdded") { - replayed.push(msg.params.message.text); - } - }); - ws.addEventListener("close", ({ code, reason }) => fail({ closed: { code, reason } })); - ws.addEventListener("error", cause => fail({ error: String(cause) })); - await new Promise((resolve, reject) => { - ws.addEventListener("open", () => resolve()); - ws.addEventListener("error", cause => reject(new Error("WebSocket error", { cause }))); - }); - - // Let user code run and buffer the two console.log calls in InspectorConsoleAgent, - // then send Console.enable so enable() replays them with no JS on the stack. - await send("Inspector.enable"); - await send("Inspector.initialized"); - await Promise.race([bufferedPromise, child.exited]); - // enable() dispatches the buffered Console.messageAdded events synchronously before - // replying, so once this resolves the replayed[] array is complete. A second round-trip - // guards against any cross-thread delivery reordering. - reply = await send("Console.enable"); - await send("Runtime.evaluate", { expression: "1" }); - } finally { - ws.close(); - child.kill(); - } - - await Promise.all([child.exited, stderrDrained.catch(() => {}), stdoutDrained]); - // Without the WebKit-side fix the inspectee SIGABRTs ("Unchecked JS exception: - // getOwnNonIndexPropertyNames ... unchecked as of get") inside toInspectorValue before - // replying to Console.enable, so the socket closes 1006 and reply is { closed: ... }. - if (child.signalCode === "SIGABRT") { - throw new Error(`inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`); - } - expect(reply).toMatchObject({ id: expect.any(Number), result: {} }); - expect(replayed).toEqual(expect.arrayContaining(["BUFFER-A", "BUFFER-B"])); - }, -); - describe("http metadata endpoint", () => { let metadataInspectee: Subprocess | undefined; diff --git a/test/internal/source-lints/webkit-prebuilt-url.test.ts b/test/internal/source-lints/webkit-prebuilt-url.test.ts index 3272c456e7a1..5a7ac2701e94 100644 --- a/test/internal/source-lints/webkit-prebuilt-url.test.ts +++ b/test/internal/source-lints/webkit-prebuilt-url.test.ts @@ -123,12 +123,4 @@ describe("WebKit prebuilt URL", () => { test("WEBKIT_VERSION is either a 40-hex sha or an autobuild-* tag", () => { expect(/^[0-9a-f]{40}$/.test(WEBKIT_VERSION) || WEBKIT_VERSION.startsWith("autobuild-")).toBe(true); }); - - // autobuild-preview-pr-* tags point at PR-branch commits that are not on - // oven-sh/WebKit main and are pre-releases with no retention guarantee; main - // must pin a 40-hex sha from a merged autobuild- release. Preview pins - // are fine on a branch while iterating; this test is the merge gate. - test("WEBKIT_VERSION is not an autobuild-preview-* tag (main must pin a merged autobuild- release)", () => { - expect(WEBKIT_VERSION.startsWith("autobuild-preview-")).toBe(false); - }); }); diff --git a/test/no-validate-leaksan.txt b/test/no-validate-leaksan.txt index a98ceb504c3b..a54d3926368c 100644 --- a/test/no-validate-leaksan.txt +++ b/test/no-validate-leaksan.txt @@ -231,6 +231,7 @@ test/js/node/test/parallel/test-child-process-windows-hide.js test/cli/inspect/BunFrontendDevServer.test.ts test/cli/inspect/HTTPServerAgent.test.ts test/cli/inspect/inspect.test.ts +test/cli/inspect/inspect-exception-checks.test.ts test/cli/install/bun-publish.test.ts test/cli/install/catalogs.test.ts test/cli/run/self-reference.test.ts From 61f207cf4f867da552bdbf49d22dfcfd2ec455eb Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 16:07:33 +0000 Subject: [PATCH 5/5] [autofix.ci] apply automated fixes --- test/cli/inspect/inspect-exception-checks.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/cli/inspect/inspect-exception-checks.test.ts b/test/cli/inspect/inspect-exception-checks.test.ts index 25c921706440..352a6caf79bc 100644 --- a/test/cli/inspect/inspect-exception-checks.test.ts +++ b/test/cli/inspect/inspect-exception-checks.test.ts @@ -104,9 +104,7 @@ test.skipIf(!isDebug && !isASAN)( // getOwnNonIndexPropertyNames ... unchecked as of get") inside toInspectorValue before // replying to Console.enable, so the socket closes 1006 and reply is { closed: ... }. if (child.signalCode === "SIGABRT") { - throw new Error( - `inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`, - ); + throw new Error(`inspectee aborted under validateExceptionChecks (reply=${JSON.stringify(reply)}):\n${stderr}`); } expect(reply).toMatchObject({ id: expect.any(Number), result: {} }); expect(replayed).toEqual(expect.arrayContaining(["BUFFER-A", "BUFFER-B"]));