fix(glob): count escape backslashes at the right offset in detect_glob_syntax - #36504
fix(glob): count escape backslashes at the right offset in detect_glob_syntax#36504robobun wants to merge 3 commits into
Conversation
…b_syntax detect_glob_syntax searches for special tokens in a slice that advances past escaped occurrences, but counted preceding backslashes at the slice-relative index into the full pattern. After skipping one escaped token, every later token was checked at the wrong offset, so patterns like \*x* were reported as having no glob syntax. bun install then treats such a workspaces entry as a literal path instead of expanding it (WorkspaceMap.rs). Rebase the match index onto the full pattern before counting, and add unit tests covering escaped, unescaped, and escaped-then-unescaped tokens. Adopts #34275. Co-authored-by: Sam Gammon <sam@elide.dev>
|
Warning Review limit reached
Next review available in: 20 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
LGTM — one-line offset fix with clear mechanism and both unit + e2e coverage.
What was reviewed:
- Verified the rebase arithmetic:
sliceis always a suffix ofpotential_pattern, solen - slice.len() + idxis the correct absolute index with no under/overflow. - Confirmed
WorkspaceMap.rsis the only caller; blast radius is limited to workspace glob detection. - Integration test uses
tempDir/bunEnv, drains pipes concurrently, asserts positive lockfile contents (not just error absence), and skips Windows with a stated reason.
Extended reasoning...
Overview
Single-line logic fix in src/glob/lib.rs::detect_glob_syntax: the loop that counts preceding backslashes was indexing potential_pattern with a slice-relative index. Since slice shrinks after each escaped match, the second and later hits per token counted backslashes at the wrong offset. The fix rebases idx onto the full pattern via potential_pattern.len() - slice.len() + idx. Three new Rust unit tests cover unescaped, escaped, and escaped-then-unescaped cases; a new bun install test in bad-workspace.test.ts exercises the only production caller end-to-end.
Security risks
None. This is a pure detection heuristic over a workspace pattern string with no allocation, syscalls, or untrusted-length arithmetic. The change strictly makes detection more accurate (previously-missed globs now detected); it cannot cause a pattern that was correctly rejected to be accepted.
Level of scrutiny
Low. The change is one arithmetic expression whose correctness is verifiable by inspection: slice is always &potential_pattern[offset..], so potential_pattern.len() - slice.len() recovers offset, and adding idx (which is < slice.len()) yields a valid index into potential_pattern. Grep confirms the only caller is workspace expansion in src/install/lockfile/Package/WorkspaceMap.rs, matching the PR's claim.
Other factors
The added tests follow repo conventions (tempDir with using, Promise.all on stdout/stderr/exited, bunEnv/bunExe, exit-code assertion last, Windows skip with a comment naming why). The integration test asserts the lockfile actually contains the linked workspace, so it fails for the right reason rather than merely checking the error string is absent. No prior reviews or outstanding comments on the timeline.
There was a problem hiding this comment.
LGTM — one-line index rebase in detect_glob_syntax is correct; slice is always a suffix of potential_pattern, so len - slice.len() + idx is the absolute offset and can't overflow or go out of bounds.
What was reviewed:
- Traced the loop:
sliceonly ever re-slices forward frompotential_pattern, so the offset math holds on every iteration. - Confirmed
WorkspaceMap.rsis the only caller; no other sibling site to fix. - New e2e test drains pipes concurrently, uses
using/tempDir, and the Windows skip is justified (*is illegal in NTFS filenames). - Unit tests cover all four tokens plus the negative case (
\\*x\\*→ false).
Extended reasoning...
Overview
One-line fix in src/glob/lib.rs::detect_glob_syntax: the backslash-counting loop was indexing potential_pattern with a slice-relative idx, so after the first escaped token was skipped the escape count was read from the wrong bytes. The fix rebases idx to an absolute offset via potential_pattern.len() - slice.len() + idx. Since slice is only ever assigned as a forward suffix of potential_pattern (slice = &slice[idx + 1..]), slice.len() <= potential_pattern.len() and idx < slice.len(), so the expression is always in [0, potential_pattern.len()) — no panic or wrap risk. The rest of the loop already indexed potential_pattern[i - 1], so this is purely making i mean what the existing code assumed it meant.
Three new #[cfg(test)] unit tests cover unescaped tokens, escaped tokens, even-backslash-count, and the regression case (escaped-then-unescaped) for each of * { [ ?, plus a negative assertion. A new e2e test in bad-workspace.test.ts exercises the sole caller (workspace glob expansion) end-to-end and asserts on the lockfile contents.
Security risks
None. Pure byte-level string scanning over a workspace-config value; no allocation, no I/O, no user code invoked. The only behavioral change is that some patterns previously mis-classified as literals are now correctly treated as globs — which is what the user wrote.
Level of scrutiny
Low. The function is 30 lines, self-contained, and has exactly one caller (src/install/lockfile/Package/WorkspaceMap.rs:213). The bug and fix are both mechanically verifiable by tracing two iterations of the loop on \\*x*. The affected input shape (an escaped glob metachar followed by an unescaped one of the same kind in a workspaces array entry) is exotic enough that blast radius is minimal.
Other factors
The comment-cop feedback about over-commenting was addressed in 00ae8b9 (thread resolved); the file now carries only the original two-line comment. Test follows harness conventions: tempDir + using, Bun.spawn with await using, concurrent Promise.all drain, exit-code asserted last, skipIf(isWindows) with a reason. The PR description states the e2e test fails on main with Workspace not found and passes with the fix, and the unit tests independently pin the invariant.
|
Updated 11:22 PM PT - Jul 30th, 2026
✅ @robobun, your commit 00ae8b9af42ff89acb8b2fbfac55321a6f25433c passed in 🧪 To try this PR locally: bunx bun-pr 36504That installs a local version of the PR into your bun-36504 --bun |
|
Superseded. main fixed this in 2c5c312 (#37052): the backslash scan in |
Adopts #34275 by @sgammon (fix and Rust unit tests are theirs); this PR adds an end-to-end
bun installtest that exercises the only caller.Problem
detect_glob_syntaxinsrc/glob/lib.rssearches each special token (*,{,[,?) in aslicethat advances past escaped occurrences, but counts the preceding backslashes at the slice-relative index into the full pattern:The first hit for each token is correct (
slice == potential_pattern), so the bug only fires after at least one escaped occurrence has been skipped. Walking\*x*: the first*is correctly seen as escaped and skipped; the second*at slice index 1 then checkspotential_pattern[0](the backslash at the front of the string, not thexthat actually precedes it) and is wrongly treated as escaped too, so the function returnsfalse.The only caller is workspace expansion in
bun install(src/install/lockfile/Package/WorkspaceMap.rs), so aworkspacesentry with an escaped token followed by an unescaped one of the same kind is treated as a literal path instead of being glob-expanded:{ "name": "root", "workspaces": ["\\*x*"] }Fix
Rebase the match index onto the full pattern before counting:
Verification
cargo test -p bun_glob: 3 new unit tests pass (unescaped tokens, escaped tokens, escaped-then-unescaped regression).test/cli/install/bad-workspace.test.ts: new test creates a*xpkg/workspace and a rootworkspaces: ["\\*x*"];bun installnow expands the glob and links the workspace. Fails onmainwithWorkspace not found "\*x*", passes with this change. Skipped on Windows (*is not a valid filename character there).no test proof · iteration 0 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/cli/install/bad-workspace.test.ts