Files
bun.sh/test/regression/issue/test_env_loader_threading.test.ts
robobun edea077947 Fix env_loader allocator threading issue with BUN_INSPECT_CONNECT_TO (#22206)
## Summary
- Fixed allocator threading violation when `BUN_INSPECT_CONNECT_TO` is
set
- Created thread-local `env_loader` with proper allocator isolation in
debugger thread
- Added regression test to verify the fix works correctly

## Problem
When `BUN_INSPECT_CONNECT_TO` environment variable is set, Bun creates a
debugger thread that spawns its own `VirtualMachine` instance.
Previously, this VM would fall back to the global `DotEnv.instance`
which was created with the main thread's allocator, causing threading
violations when the debugger thread accessed environment files via
`--env-file` or other env loading operations.

## Solution
Modified `startJSDebuggerThread` in `src/bun.js/Debugger.zig` to:
1. Create a thread-local `DotEnv.Map` and `DotEnv.Loader` using the
debugger thread's allocator
2. Pass this thread-local `env_loader` to `VirtualMachine.init()` to
ensure proper allocator isolation
3. Prevent sharing of allocators across threads

## Test plan
- [x] Added regression test in
`test/regression/issue/test_env_loader_threading.test.ts`
- [x] Verified basic Bun functionality still works
- [x] Test passes with both normal execution and with
`BUN_INSPECT_CONNECT_TO` set

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-28 17:16:37 -07:00

59 lines
2.2 KiB
TypeScript

import { spawn } from "bun";
import { expect, test } from "bun:test";
import { bunExe, tempDirWithFiles } from "harness";
test("env_loader should not have allocator threading issues with BUN_INSPECT_CONNECT_TO", async () => {
const dir = tempDirWithFiles("env-loader-threading", {
".env": "TEST_ENV_VAR=hello_world",
"index.js": `console.log(process.env.TEST_ENV_VAR || 'undefined');`,
});
// This test verifies that when BUN_INSPECT_CONNECT_TO is set,
// the debugger thread creates its own env_loader with proper allocator isolation
// and doesn't cause threading violations when accessing environment files.
// First, test normal execution without inspector to establish baseline
const normalProc = spawn({
cmd: [bunExe(), "index.js"],
cwd: dir,
env: {
...Bun.env,
TEST_ENV_VAR: undefined, // Remove from process env to test .env loading
},
stdio: ["inherit", "pipe", "pipe"],
});
const normalResult = await normalProc.exited;
const normalStdout = await normalProc.stdout.text();
expect(normalResult).toBe(0);
expect(normalStdout.trim()).toBe("hello_world");
// Now test with BUN_INSPECT_CONNECT_TO set to a non-existent socket
// This should trigger the debugger thread creation without actually connecting
const inspectorProc = spawn({
cmd: [bunExe(), "index.js"],
cwd: dir,
env: {
...Bun.env,
BUN_INSPECT_CONNECT_TO: "/tmp/non-existent-debug-socket",
TEST_ENV_VAR: undefined, // Remove from process env to test .env loading
},
stdio: ["inherit", "pipe", "pipe"],
});
const inspectorResult = await inspectorProc.exited;
const inspectorStdout = await inspectorProc.stdout.text();
const inspectorStderr = await inspectorProc.stderr.text();
// The process should still work correctly and load .env file
expect(inspectorResult).toBe(0);
expect(inspectorStdout.trim()).toBe("hello_world");
// Should not have any allocator-related errors or panics
expect(inspectorStderr).not.toContain("panic");
expect(inspectorStderr).not.toContain("allocator");
expect(inspectorStderr).not.toContain("thread");
expect(inspectorStderr).not.toContain("assertion failed");
}, 10000); // 10 second timeout for potential debugger connection attempts