mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
test: address review comments for issue #26660
- Replace tempDir-based tests with inline scripts using -e flag - Remove forbidden stderr string-absence assertions - Add error path test case for failing commands Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,15 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDir } from "harness";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
|
||||
// Test for issue #26660: Shell interpreter crash when spawning many concurrent shell commands
|
||||
// The bug was that IOWriter could have pending chunks referencing freed memory after
|
||||
// builtin/cmd cleanup, causing use-after-free crashes.
|
||||
test("many concurrent shell commands should not crash", async () => {
|
||||
// Create a test script that spawns many shell commands concurrently
|
||||
// This is similar to what OpenCode does which triggered the original crash
|
||||
using dir = tempDir("issue-26660", {
|
||||
"test.ts": `
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
// Spawn 60 shell commands concurrently (similar to the crash report)
|
||||
for (let i = 0; i < 60; i++) {
|
||||
promises.push(
|
||||
Bun.$\`echo "Hello from shell \${i}"\`.text().then(() => {})
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
console.log("All shell commands completed successfully");
|
||||
`,
|
||||
});
|
||||
// Spawn many shell commands concurrently (similar to what triggered the crash)
|
||||
const script = `const promises = []; for (let i = 0; i < 60; i++) { promises.push(Bun.$\`echo "Hello from shell \${i}"\`.text().then(() => {})); } await Promise.all(promises); console.log("All shell commands completed successfully");`;
|
||||
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "run", "test.ts"],
|
||||
cwd: String(dir),
|
||||
cmd: [bunExe(), "-e", script],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
@@ -33,34 +17,17 @@ test("many concurrent shell commands should not crash", async () => {
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stderr).not.toContain("Segmentation fault");
|
||||
expect(stderr).not.toContain("panic");
|
||||
expect(stdout).toContain("All shell commands completed successfully");
|
||||
expect(stderr).toBe("");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("concurrent shell commands with output should not crash", async () => {
|
||||
// Test with commands that produce output, which exercises IOWriter more
|
||||
using dir = tempDir("issue-26660-output", {
|
||||
"test.ts": `
|
||||
const promises: Promise<string>[] = [];
|
||||
|
||||
// Spawn many echo commands that all write to IOWriter
|
||||
for (let i = 0; i < 40; i++) {
|
||||
promises.push(
|
||||
Bun.$\`echo "Line \${i}: This is a test with some longer output to exercise the IOWriter buffer"\`.text()
|
||||
);
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
console.log("Collected", results.length, "results");
|
||||
console.log("All outputs received correctly");
|
||||
`,
|
||||
});
|
||||
const script = `const promises = []; for (let i = 0; i < 40; i++) { promises.push(Bun.$\`echo "Line \${i}: test output"\`.text()); } const results = await Promise.all(promises); console.log("Collected", results.length, "results"); console.log("All outputs received correctly");`;
|
||||
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "run", "test.ts"],
|
||||
cwd: String(dir),
|
||||
cmd: [bunExe(), "-e", script],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
@@ -68,33 +35,17 @@ test("concurrent shell commands with output should not crash", async () => {
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stderr).not.toContain("Segmentation fault");
|
||||
expect(stderr).not.toContain("panic");
|
||||
expect(stdout).toContain("All outputs received correctly");
|
||||
expect(stderr).toBe("");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("shell commands with mixed builtins should not crash", async () => {
|
||||
// Test various builtins that use IOWriter
|
||||
using dir = tempDir("issue-26660-builtins", {
|
||||
"test.ts": `
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
// Spawn various builtin commands concurrently
|
||||
for (let i = 0; i < 20; i++) {
|
||||
promises.push(Bun.$\`echo "Echo \${i}"\`.text().then(() => {}));
|
||||
promises.push(Bun.$\`pwd\`.text().then(() => {}));
|
||||
promises.push(Bun.$\`true\`.text().then(() => {}));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
console.log("All builtin commands completed");
|
||||
`,
|
||||
});
|
||||
const script = `const promises = []; for (let i = 0; i < 20; i++) { promises.push(Bun.$\`echo "Echo \${i}"\`.text().then(() => {})); promises.push(Bun.$\`pwd\`.text().then(() => {})); promises.push(Bun.$\`true\`.text().then(() => {})); } await Promise.all(promises); console.log("All builtin commands completed");`;
|
||||
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "run", "test.ts"],
|
||||
cwd: String(dir),
|
||||
cmd: [bunExe(), "-e", script],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
@@ -102,8 +53,24 @@ test("shell commands with mixed builtins should not crash", async () => {
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stderr).not.toContain("Segmentation fault");
|
||||
expect(stderr).not.toContain("panic");
|
||||
expect(stdout).toContain("All builtin commands completed");
|
||||
expect(stderr).toBe("");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("concurrent shell commands with failing commands should handle errors", async () => {
|
||||
// Test that failing commands are handled correctly and don't cause crashes
|
||||
const script = `const promises = []; for (let i = 0; i < 20; i++) { if (i % 3 === 0) { promises.push(Bun.$\`nonexistent_command_\${i}\`.nothrow().text().catch(() => "failed")); } else { promises.push(Bun.$\`echo "Success \${i}"\`.text()); } } const results = await Promise.all(promises); console.log("Handled", results.length, "commands"); console.log("Error handling completed");`;
|
||||
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "-e", script],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stdout).toContain("Error handling completed");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user