From 00b7eab9faeac851f961ea6cde9b8cdc2b5acaa2 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Mon, 11 May 2026 09:37:05 +0000 Subject: [PATCH] Fix capacity under-allocation in ESMConditions.init The expression `if (allow_addons) 1 else 0 + conditions.len` parses as `if (allow_addons) 1 else (0 + conditions.len)`, so when allow_addons is true (the default), conditions.len was dropped from the capacity calculation and putAssumeCapacity would overflow the map when enough user conditions were passed to Bun.build. --- src/bundler/options.zig | 7 ++++--- test/bundler/bun-build-api.test.ts | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bundler/options.zig b/src/bundler/options.zig index daea5ced59a3..e2cca4ba92a5 100644 --- a/src/bundler/options.zig +++ b/src/bundler/options.zig @@ -1087,9 +1087,10 @@ pub const ESMConditions = struct { var require_condition_map = ConditionsMap.init(allocator); var style_condition_map = ConditionsMap.init(allocator); - try default_condition_amp.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); - try import_condition_map.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); - try require_condition_map.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); + const addons: usize = if (allow_addons) 1 else 0; + try default_condition_amp.ensureTotalCapacity(defaults.len + 2 + addons + conditions.len); + try import_condition_map.ensureTotalCapacity(defaults.len + 2 + addons + conditions.len); + try require_condition_map.ensureTotalCapacity(defaults.len + 2 + addons + conditions.len); try style_condition_map.ensureTotalCapacity(defaults.len + 2 + conditions.len); import_condition_map.putAssumeCapacity("import", {}); diff --git a/test/bundler/bun-build-api.test.ts b/test/bundler/bun-build-api.test.ts index c1112743f02c..07de7d2d4868 100644 --- a/test/bundler/bun-build-api.test.ts +++ b/test/bundler/bun-build-api.test.ts @@ -649,6 +649,27 @@ describe("Bun.build", () => { expect(await html?.text()).toContain(""); }, ); + + test.concurrent("many custom conditions does not crash", async () => { + const dir = tempDirWithFiles("bun-build-api-many-conditions", { + "entry.js": "export const x = 1;\n", + }); + const conditions = Array.from({ length: 64 }, (_, i) => "cond" + i); + await using proc = Bun.spawn({ + cmd: [ + bunExe(), + "-e", + `const r = await Bun.build({ entrypoints: [${JSON.stringify(join(dir, "entry.js"))}], conditions: ${JSON.stringify(conditions)} }); if (!r.success) throw new AggregateError(r.logs); console.log("ok");`, + ], + env: bunEnv, + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + expect(stderr).toBe(""); + expect(stdout).toBe("ok\n"); + expect(exitCode).toBe(0); + }); }); test.concurrent("macro with nested object", async () => {