shell_parser: drop stale capacity==1 debug_assert in parse_atom#31191
Conversation
BabyVec::with_capacity_in(1) routes through grow_to which floors the allocation at 4 slots, so atoms.capacity() is never 1. The assertion was a stack-fallback check carried over from the Zig port and does not guard any invariant in the Rust implementation. Every single-atom parse (e.g. `echo foo`) tripped it in debug builds since 303cd28 introduced BabyVec as the ArenaVec backing.
|
Updated 2:49 PM PT - May 21st, 2026
✅ @robobun, your commit f86c738b42c1d050c54dc05a2ffa1e86ffd697c5 passed in 🧪 To try this PR locally: bunx bun-pr 31191That installs a local version of the PR into your bun-31191 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughSimplifies the single-atom branch in ChangesParse atom debug assertion cleanup
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Re: duplicates —
|
There was a problem hiding this comment.
LGTM — the removed debug_assert is provably always-false given BabyVec's min-capacity-4 growth policy, and it guarded no invariant in the Rust port.
Extended reasoning...
Overview
This PR removes a single debug_assert!(atoms.capacity() == 1) from Parser::parse_atom in src/shell_parser/parse.rs and adds a regression test for single-atom parsing (ls, echo ~) in test/js/bun/shell/parse.test.ts.
Correctness
I verified the root cause directly: ArenaVec is aliased to BabyVec (src/bun_alloc/lib.rs:280), and BabyVec::with_capacity_in(1, ..) calls grow_to(1) which computes new_cap = (0).max(1).max(4) = 4 (src/bun_alloc/baby_vec.rs:344-346). The assertion therefore fires on every single-atom token in debug builds. The assertion was a vestige of the Zig stack-fallback allocator and guards no invariant here — the len() == 1 match arm already establishes everything the code relies on. Release builds are unaffected since debug_assert! compiles out.
Security risks
None. This is a pure deletion of a debug-only assertion with no control-flow, data-handling, or boundary changes.
Level of scrutiny
Low. A one-line removal of a provably-stale debug assertion, plus an additive test that follows existing patterns in the same file. The CI failures reported by robobun are unrelated build-infrastructure issues (clang -no-pie linker warnings and scripts/build/ci.ts build failures) that affect the base branch, not this diff.
Other factors
No CODEOWNERS entry covers src/shell_parser/. No prior human review comments are outstanding. The bug-hunting system found no issues.
Fuzzilli found a debug-build panic in the shell parser:
Minimal repro (debug build):
Root cause
parse_atomcreates its atom list withArenaVec::with_capacity_in(1, ..)and, when exactly one atom was pushed, assertsatoms.capacity() == 1. In the Zig original this verified thestd.heap.stackFallback(@sizeOf(SimpleAtom))slot was sufficient and no heap allocation occurred.Since 303cd28,
ArenaVecisBabyVec, whosewith_capacity_inroutes throughgrow_to:so the initial capacity is always 4. The assertion therefore fires on every single-atom token in debug builds — i.e. on essentially any
Bun.$invocation.Fix
Remove the assertion. There is no stack fallback in the Rust port, so the check guards no invariant; the
len() == 1match arm already establishes the only property the code relies on.Covered by the existing
test/js/bun/shell/parse.test.ts(parse\echo foo`et al.), which crashed underbun-debug` before this change and passes after.