-
Notifications
You must be signed in to change notification settings - Fork 5k
Fix crash in Bun.build when passing many conditions #30498
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
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
🟣 Heads-up (pre-existing, not a blocker): the same if-expression precedence footgun this PR fixes also lives in
loadersFromTransformOptions()at src/bundler/options.zig:1574-1577 — whentarget.isBun()is true, theelsebranch greedily swallows the trailing+ ... + default_loader_ext.len, so the capacity reservation drops 16+ entries. It doesn't crash there because the subsequent inserts usegetOrPutValue()(which grows the map) rather thanputAssumeCapacity(), so the only effect is a missed pre-reservation; might be worth applying the same@intFromBoolfix while you're here for consistency.Extended reasoning...
What & where
loadersFromTransformOptions()computes the initial capacity for the loaders map as:This is the identical Zig if-expression precedence footgun that this PR just fixed in
ESMConditions.init. Zig parses theelsebranch greedily, so the trailing+expressions bind into theelserather than into the outer sum.Step-by-step evaluation
Take
target = .bun(sotarget.isBun() == true,target == .browser == false),default_loader_ext_bun.len = 2,default_loader_ext_browser.len = 1,default_loader_ext.len = 18, and sayinput_loaders.extensions.len = 0:if (target == .browser) 1 else (0 + 18)→ since false, evaluates to18. (This branch is fine-ish on its own.)if (target.isBun()) 2 else (0 + <inner>)→ since true, evaluates to2. The entireelse (0 + 18)arm — includingdefault_loader_ext.len— is discarded.0 + 2= 2.The author clearly intended
0 + 2 + 0 + 18 = 20. So the map is reserved for 2 entries instead of 20.Why it doesn't crash (addressing the "already handled" objection)
Unlike
ESMConditions.init, this site is saved by two things:stringHashMapFromArraysonly callsputAssumeCapacityfor theinput_loaders.extensionskeys, andinput_loaders.extensions.lenis the one term that's always included in the sum (it's outside theif), so those inserts never overflow.default_loader_ext/default_loader_ext_bun/default_loader_ext_browserinserts usegetOrPutValue(), which grows the map on demand.So there is no correctness or memory-safety impact today — just a few unnecessary rehashes during option setup. I agree with the objection that this is not a functional bug.
Why it's still worth mentioning on this PR
This PR's entire premise is that
a + if (b) 1 else 0 + cis a footgun that silently miscomputes capacity and that@intFromBoolis the safer spelling. The same miscomputed-by-construction expression sits ~480 lines away in the same file. The intent of that code was clearly to reserve space for all the default extensions; it just happens that the consumer is forgiving. If anyone later swapsgetOrPutValueforputAssumeCapacity(matching the pattern this PR just fixed), it becomes the same crash.Suggested fix
Same transformation as in this PR:
(or just parenthesize the
ifexpressions). Purely a consistency/cleanup suggestion — not a blocker for this PR.