-
Notifications
You must be signed in to change notification settings - Fork 5k
Fix capacity miscount in ESMConditions.init #30692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -167,3 +167,22 @@ it("custom condition when don't match condition should resolves to default", asy | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(exitCode).toBe(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // https://github.com/oven-sh/bun/issues/30619 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it("many custom conditions resolve correctly", async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const n of [4, 5, 6, 8, 12, 20]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const flags = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 1; i < n; i++) flags.push(`--conditions=c${i}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| flags.push("--conditions=first"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { exitCode, stdout, stderr } = Bun.spawnSync({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd: [bunExe(), ...flags, `${dir}/test.js`], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: bunEnv, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cwd: import.meta.dir, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect({ n, exitCode, stdout: stdout.toString("utf8"), stderr: stderr.toString("utf8") }).toMatchObject({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exitCode: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stdout: "1\n", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+172
to
+188
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win Use parameterized test cases instead of a manual loop. This should be split into parameterized cases so each ♻️ Suggested rewrite-it("many custom conditions resolve correctly", async () => {
- for (const n of [4, 5, 6, 8, 12, 20]) {
- const flags = [];
- for (let i = 1; i < n; i++) flags.push(`--conditions=c${i}`);
- flags.push("--conditions=first");
- const { exitCode, stdout, stderr } = Bun.spawnSync({
- cmd: [bunExe(), ...flags, `${dir}/test.js`],
- env: bunEnv,
- cwd: import.meta.dir,
- });
- expect({ n, exitCode, stdout: stdout.toString("utf8"), stderr: stderr.toString("utf8") }).toMatchObject({
- n,
- exitCode: 0,
- stdout: "1\n",
- });
- }
-});
+it.concurrent.each([4, 5, 6, 8, 12, 20])("many custom conditions resolve correctly (n=%i)", async n => {
+ const flags = [];
+ for (let i = 1; i < n; i++) flags.push(`--conditions=c${i}`);
+ flags.push("--conditions=first");
+
+ const { exitCode, stdout, stderr } = Bun.spawnSync({
+ cmd: [bunExe(), ...flags, `${dir}/test.js`],
+ env: bunEnv,
+ cwd: import.meta.dir,
+ });
+
+ expect({ n, exitCode, stdout: stdout.toString("utf8"), stderr: stderr.toString("utf8") }).toMatchObject({
+ n,
+ exitCode: 0,
+ stdout: "1\n",
+ });
+});Based on learnings, in 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 This PR's only source change is to
src/bundler/options.zig, but persrc/CLAUDE.mdthe.zigfiles are non-compiled porting references — the shipped binary is built fromsrc/bundler/options.rs, whereESMConditions::initalready hoistsaddon_extraand uses growing.insert(), so the bug described in the PR body cannot occur there. On top of that, commit 28128c6 reverted theESMConditions.inithunk from 1e2c22c, so the net diff doesn't even touch that function — only the cosmetic parenthesization ofloadersFromTransformOptions(which usesgetOrPutValueand was never UB) survives. Net effect: the.zigedit changes nothing in the built binary and the title/description are misleading; only the two new regression tests add value. Please verify whether #30619 still reproduces onmain(post-Rust-rewrite) — if not, retitle as a tests-only PR; if it does, the fix needs to go in.rs.Extended reasoning...
What this PR actually changes
The PR title is "Fix capacity miscount in ESMConditions.init" and the description claims to fix #30619 by hoisting
if (allow_addons) 1 else 0into a typed local. But the net diff against base forsrc/bundler/options.zigshows zero changes toESMConditions.init— onlyloadersFromTransformOptions(lines 1574-1577) is modified, adding parentheses around two if/else expressions in a capacity hint.This happened because commit 28128c6 ("Also fix if/else precedence in loadersFromTransformOptions capacity hint") accidentally reverted the
ESMConditions.initfix from 1e2c22c.git show 28128c64 -- src/bundler/options.zigshows it removingconst addons_extra: usize = if (allow_addons) 1 else 0;and restoring the original buggy expression:At HEAD,
src/bundler/options.zig:1090-1092still reads the unparenthesized form, which Zig parses asdefaults.len + 2 + (if (allow_addons) 1 else (0 + conditions.len)).Why none of this affects the binary
More fundamentally,
src/CLAUDE.md(lines 15-17) states:The base of this PR is one commit after 23427db "Rewrite Bun in Rust (#30412)". There is no top-level
build.zig, and all CI build failures in this PR's timeline are in.rsfiles (Blob.rs,server/mod.rs,h2_frame_parser.rs,JSSecrets.rs,VirtualMachine.rs,process.rs) — there is no Zig build step. The compiled implementation issrc/bundler/options.rs.Inspecting
src/bundler/options.rs:832-835, the Rust port ofESMConditions::initalready computes capacity correctly:and at line ~838 it uses
.insert()(which grows on demand) rather than an assume-capacity variant — the comment// PERF(port): was assume_capacityconfirms this was intentionally changed during the port. So even if the reserve hint were wrong, the Rust code could not exhibit theputAssumeCapacityoverflow / debug assert described in the PR body. Similarly,loaders_from_transform_optionsin options.rs already sums its terms correctly (Rust if/else with braces doesn't have Zig's precedence trap).Step-by-step proof
git diff 19d8ade2..HEAD -- src/bundler/options.zigtouches only lines 1574-1577 inloadersFromTransformOptions.ESMConditions.initis byte-identical to base.loadersFromTransformOptionscallsstringHashMapFromArrays(which onlyputAssumeCapacity'sinput_loaders.extensions— always ≤ the hint regardless of precedence) and then usesgetOrPutValuefor the default extensions, which grows the map safely. The added parentheses fix the hint arithmetic but there was never UB here.src/bundler/options.zigis a reference-only sibling ofsrc/bundler/options.rsper project conventions. Editing it cannot change the built binary.ESMConditions::initin options.rs already hoistsaddon_extraand uses growing.insert(). With 12 user conditions andallow_addons=true, it reserves2 + 2 + 1 + 12 = 17and inserts via.insert()— no overflow possible.mainwith or without this PR's.zigedit, because they exercise the Rust runtime. The.zigchange has zero runtime effect.Impact and how to fix
The PR as written does not deliver what its title and "Fixes #30619" claim. The actionable outcomes are:
options.zigedit (or at minimum re-apply the revertedESMConditions.inithunk so the reference file stays internally consistent — but persrc/CLAUDE.md, new code shouldn't go in.zigfiles at all).main. Given options.rs is already correct, it almost certainly doesn't — in which case this PR should be retitled to "Add regression tests for bun --conditions: export condition matching breaks with 4+ conditions (falls back to default) #30619" and the description updated to note the bug was fixed by the Rust rewrite..rscode and needs to be found and fixed there; editingoptions.zigcannot help.