test scanner: skip paths exceeding MAX_PATH_BYTES instead of panicking - #32412
test scanner: skip paths exceeding MAX_PATH_BYTES instead of panicking#32412robobun wants to merge 3 commits into
Conversation
The test file scanner walks the directory tree by repeatedly joining parent directory paths with entry names into a fixed-size PathBuffer (MAX_PATH_BYTES: 1024 macOS, 4096 Linux). When a tree is deep enough that the absolute path exceeds this limit, the unchecked join panics in normalize_string_generic_tz with a slice index error. Use the existing checked join variant at each join site in the scanner and skip entries whose joined path would overflow. The OS would reject such paths with ENAMETOOLONG anyway, so skipping is the correct behavior rather than aborting the entire test run. Fixes Sentry BUN-3JDD.
|
Updated 1:01 PM PT - Jun 16th, 2026
✅ @robobun, your commit f596e11ba7616727c772a2e44e84ad5f37529795 passed in 🧪 To try this PR locally: bunx bun-pr 32412That installs a local version of the PR into your bun-32412 --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)
Walkthrough
ChangesScanner checked path construction and regression test
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
On musl (Alpine), getcwd(3) fails once the cumulative path exceeds PATH_MAX. bash prints a cd warning for each subsequent level but mkdir/cd still succeed and exit 0. Filter the known warning before asserting stderr is clean, matching the existing handling in test/js/bun/glob/path-length.test.ts.
There was a problem hiding this comment.
LGTM — the musl stderr filter was applied in f596e11, and the checked-join swap looks correct.
Extended reasoning...
Overview
This PR fixes a Sentry-reported panic (range end index N out of range for slice of length 1023/4095) in the bun test file scanner. It touches two files: src/runtime/cli/test/Scanner.rs swaps every unchecked abs_buf / join_abs_string_buf call for the existing _checked variants that return Option, and handles None by skipping the entry (or returning ScanError::DoesNotExist for the initial scan argument). test/cli/test/bun-test.test.ts adds a regression test that builds a directory chain past MAX_PATH_BYTES and asserts bun test runs the shallow test instead of panicking.
Security risks
None. This is a defensive bounds-check change in the test-file discovery scanner. No auth, crypto, network, or permission logic is touched; the only behavioral change is that pathologically deep directory entries are silently skipped (the OS would have rejected them with ENAMETOOLONG anyway) instead of aborting the whole process.
Level of scrutiny
Low–medium. The transformation is mechanical: each call site goes from foo(...).len() / foo(...) to a let Some(...) = foo_checked(...) else { skip } pattern. The Windows branch was refactored to inline what abs_buf_z did (checked join + manual NUL byte + ZStr::from_raw), mirroring the non-Windows branch directly above it; reserving buf_len - 1 bytes for the join so the NUL fits at open_dir_buf[path2_len] is correct. abs_buf_checked and join_abs_string_buf_checked are pre-existing helpers in resolver/lib.rs and paths/resolve_path.rs, not new code.
Other factors
I previously flagged that the new test's setup-stderr assertion would fail on musl CI due to bash getcwd warnings; the author applied the same filter used in test/js/bun/glob/path-length.test.ts in f596e11 and resolved the thread. The bug-hunting pass on the latest revision found no issues. The Buildkite musl failure in the robobun comment is an LTO/llvm-link data-layout build infrastructure error, unrelated to the source changes here. No CODEOWNERS apply to these paths.
|
Issue #35728 reports the same panic ("range end index N out of range for slice of length 1023") reached from a different direction: a single Branch |
|
Superseded by #35863, which carries the same Scanner changes rebased onto current main and additionally bounds |
|
Closing this one. #35863 now carries exactly this Scanner change rebased onto current main (the extra |
Fixes Sentry BUN-3JDD (
Panic: range end index 1041 out of range for slice of length 1023).Repro
Stack:
bun test→Scanner::scan→abs_buf→join_abs_string_buf<Loose>→_join_abs_string_buf→normalize_string_buf→normalize_string_generic_tz→core::slice::index::slice_index_fail.Cause
The test scanner walks the tree by joining
[parent_abs_path, entry_name]into a fixedPathBuffer([u8; MAX_PATH_BYTES]: 1024 on macOS, 4096 on Linux)._join_abs_string_bufconcatenates the parts into an unboundedJoinScratch(heap-grows pastMAX_PATH_BYTES), then callsnormalize_string_bufwith the fixed output buffer sliced tobuf[leading_len..](1023 / 4095 bytes after the leading/).normalize_string_generic_tzcopies each segment with no bounds check atresolve_path.rs:1119, so the first segment that crosses the limit panics.The Zig reference (
normalizeStringGenericTZ) used an unchecked@memcpyhere, so this was pre-existing UB in the Zig build that Rust's bounds checking now catches as a panic.Fix
Switch every path join in
Scanner.rsto the existingjoin_abs_string_buf_checked/abs_buf_checkedvariant, which returnsNonewhen the normalized result does not fit. On overflow the scanner now skips that entry (directories are not descended into, files are not added) instead of aborting the wholebun testrun. The OS would reject such paths withENAMETOOLONGanyway.The initial scan path (
bun test <huge-arg>) returnsDoesNotExiston overflow, matching what the user would see from the failed open.Verification
Existing scanner / path-ignore-pattern tests all pass.