mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 06:12:08 +00:00
fix(shell): also fix u16 overflow in brace expansion output counter
The out_key_counter in expandFlat/expandNested was u16, overflowing
when cartesian product of brace groups exceeds 65535 (e.g. {a,b}
repeated 16 times = 2^16 = 65536). Changed to u32.
Added test for the cartesian product overflow case.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,7 @@ pub fn expand(
|
||||
out: []std.array_list.Managed(u8),
|
||||
contains_nested: bool,
|
||||
) ExpandError!void {
|
||||
var out_key_counter: u16 = 1;
|
||||
var out_key_counter: u32 = 1;
|
||||
if (!contains_nested) {
|
||||
var expansions_table = try buildExpansionTableAlloc(allocator, tokens);
|
||||
|
||||
@@ -74,8 +74,8 @@ pub fn expand(
|
||||
fn expandNested(
|
||||
root: *AST.Group,
|
||||
out: []std.array_list.Managed(u8),
|
||||
out_key: u16,
|
||||
out_key_counter: *u16,
|
||||
out_key: u32,
|
||||
out_key_counter: *u32,
|
||||
start: u32,
|
||||
) ExpandError!void {
|
||||
if (root.atoms == .single) {
|
||||
@@ -157,8 +157,8 @@ fn expandFlat(
|
||||
tokens: []const Token,
|
||||
expansion_table: []const ExpansionVariant,
|
||||
out: []std.array_list.Managed(u8),
|
||||
out_key: u16,
|
||||
out_key_counter: *u16,
|
||||
out_key: u32,
|
||||
out_key_counter: *u32,
|
||||
depth_: u8,
|
||||
start: usize,
|
||||
end: usize,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, isPosix } from "harness";
|
||||
|
||||
// Regression test: brace expansion with 256+ items used a u8 counter for
|
||||
// variant counting, which overflowed and caused a segfault on release builds
|
||||
// or integer overflow panic on debug builds.
|
||||
// Regression tests for brace expansion integer overflows:
|
||||
// 1. u8 variant counter overflowed at 256 items in a single brace group
|
||||
// 2. u16 out_key_counter overflowed at 65536 total cartesian product expansions
|
||||
|
||||
describe.if(isPosix)("brace expansion should handle large item counts", () => {
|
||||
test("256 items in a brace group does not crash", async () => {
|
||||
test.concurrent("256 items in a brace group does not crash", async () => {
|
||||
// Generate {x0,x1,x2,...,x255} - 256 items overflows u8
|
||||
const items = Array.from({ length: 256 }, (_, i) => `x${i}`).join(",");
|
||||
const cmd = `echo {${items}}`;
|
||||
@@ -40,7 +40,7 @@ describe.if(isPosix)("brace expansion should handle large item counts", () => {
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("500 items in a brace group does not crash", async () => {
|
||||
test.concurrent("500 items in a brace group does not crash", async () => {
|
||||
const items = Array.from({ length: 500 }, (_, i) => `y${i}`).join(",");
|
||||
const cmd = `echo {${items}}`;
|
||||
|
||||
@@ -68,4 +68,32 @@ describe.if(isPosix)("brace expansion should handle large item counts", () => {
|
||||
expect(stdout).toContain("exitCode:0");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("cartesian product exceeding 65535 does not crash", async () => {
|
||||
// {a,b} repeated 16 times = 2^16 = 65536 expansions, which overflows u16
|
||||
// Use ${{raw:...}} to pass brace expression without shell interpolation
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`
|
||||
import { $ } from "bun";
|
||||
$.throws(false);
|
||||
const r = await $\`echo $\{{ raw: "{a,b}".repeat(16) }}\`;
|
||||
const words = r.stdout.toString().trim().split(" ");
|
||||
console.log("count:" + words.length);
|
||||
console.log("exitCode:" + r.exitCode);
|
||||
`,
|
||||
],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stdout).toContain("count:65536");
|
||||
expect(stdout).toContain("exitCode:0");
|
||||
expect(exitCode).toBe(0);
|
||||
}, 30_000);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user