diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig index 895a6e90b5..1e24bbca48 100644 --- a/src/bake/DevServer.zig +++ b/src/bake/DevServer.zig @@ -592,6 +592,13 @@ pub fn deinit(dev: *DevServer) void { if (s.underlying) |websocket| websocket.close(); } + // Drain pending libuv close callbacks before freeing memory. + // libuv closes handles asynchronously — without this, close + // callbacks reference freed socket memory + if (bun.Environment.isWindows) { + const uv_loop = bun.windows.libuv.Loop.get(); + _ = bun.windows.libuv.uv_run(uv_loop, .nowait); + } dev.active_websocket_connections.deinit(alloc); }, diff --git a/test/js/bun/shell/shell-cmdsub-crash.test.ts b/test/js/bun/shell/shell-cmdsub-crash.test.ts index 2e07c3201c..a764e724f1 100644 --- a/test/js/bun/shell/shell-cmdsub-crash.test.ts +++ b/test/js/bun/shell/shell-cmdsub-crash.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { bunEnv, bunExe } from "harness"; +import { bunEnv, bunExe, isWindows } from "harness"; // Regression test for use-after-poison in builtin OutputTask callbacks // inside command substitution $(). @@ -14,7 +14,7 @@ import { bunEnv, bunExe } from "harness"; // with many /tmp entries and some permission-denied dirs reliably // triggers the ASAN use-after-poison. -describe("builtins in command substitution with errors should not crash", () => { +describe.skipIf(isWindows)("builtins in command substitution with errors should not crash", () => { test("ls /tmp/* in command substitution", async () => { await using proc = Bun.spawn({ cmd: [