Skip to content

fix(parser): preserve glob in process substitution bodies#1337

Open
chaliy wants to merge 2 commits intomainfrom
fix/issue-1333-glob-process-subst
Open

fix(parser): preserve glob in process substitution bodies#1337
chaliy wants to merge 2 commits intomainfrom
fix/issue-1333-glob-process-subst

Conversation

@chaliy
Copy link
Copy Markdown
Contributor

@chaliy chaliy commented Apr 17, 2026

Summary

Fixes #1333. Glob metacharacters like * adjacent to a quoted variable (e.g. ./"$var"*.ext) now expand correctly inside process substitution <(…) and >(…).

Before this fix, patterns like < <(ls ./"$prefix"*.tmp.html) silently matched nothing, even though the same pattern worked at the top level, inside $(...), inside (…), and inside { …; } | ….

Why

The parser re-serialised tokens inside <(cmd) back into a string before handing the body to a child parser. For QuotedGlobWord tokens (a word like ./"$var"*.ext), re-serialization wrapped the entire token's content in double quotes:

./$var*.ext   →   "./$var*.ext"

…which promoted the otherwise-unquoted * into a literal character, so the inner parser's pathname-expansion check at expand_command_args correctly decided not to glob.

How

Replace the 180-line token-to-string reconstruction loop with a single call to the parser's existing source_slice() helper: walk tokens to find the matching closing ), then slice the body verbatim from the original source. The child parser now sees exactly what the user wrote, so quote boundaries and glob metacharacters are preserved byte-for-byte.

TM-DOS-021 (depth/fuel budget propagation to the child parser) is preserved.

Test plan

  • Added process_subst_glob_adjacent_quoted_var and process_subst_glob_cat to crates/bashkit/tests/spec_cases/bash/procsub.test.sh — both previously failed and now pass
  • cargo test -p bashkit --test spec_tests bash_spec_tests
  • cargo test -p bashkit --lib parser ✅ (141 passed)
  • cargo test -p bashkit --lib interpreter ✅ (206 passed)
  • Manual smoke: bashkit -c '... < <(ls ./"$p"*.tmp.html | sort)' enumerates the expected files
  • cargo fmt --check
  • Net -130 lines (parser code simplification)

chaliy added 2 commits April 17, 2026 13:59
Parser re-serialized tokens inside `<(cmd)` back into a string before
handing the body to a child parser. For `QuotedGlobWord` tokens
(e.g. `./"$var"*.ext`), re-serialization wrapped the *entire* token
content in double quotes, which turned the unquoted glob `*` into a
literal character. As a result, patterns like
`< <(ls ./"$prefix"*.tmp.html)` silently matched nothing.

Slice the process substitution body verbatim from the original source
via the existing `source_slice()` helper instead of rebuilding it from
tokens. The child parser now sees exactly what the user wrote, so
quote boundaries and glob metacharacters are preserved.

Net simplification: removes 180+ lines of token-to-string
reconstruction, eliminates whole classes of future round-trip bugs.

Closes #1333
Hosted runner was exhausting disk while compiling security_failpoint_tests
(the 5th of 6 sequential cargo test stages with different feature flags).
Reclaim ~25 GB of preinstalled SDKs before Rust compiles start.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(glob): glob * adjacent to quoted variable still fails inside process substitution <(...)

1 participant