Skip to content

fix(expansion): preserve leading IFS boundaries - #367

Open
privatenumber wants to merge 9 commits into
fix/parameter-expansion-single-evaluationfrom
fix/leading-ifs-word-splitting
Open

fix(expansion): preserve leading IFS boundaries#367
privatenumber wants to merge 9 commits into
fix/parameter-expansion-single-evaluationfrom
fix/leading-ifs-word-splitting

Conversation

@privatenumber

Copy link
Copy Markdown
Collaborator

Problem

Unquoted array default expansion can begin with an empty element. When it followed literal text, the word splitter dropped the resulting boundary: prefix=${values[@]-fallback} could merge prefix= and the next array element into one argument. Commands then received different arguments from Bash.

Changes

The splitter now commits preceding literal text when the next unquoted expansion begins with an IFS delimiter. The change preserves the intended argument boundary and enables the matching Oils conformance case.

Stack position: child of #366; prerequisite for the structured-extglob repair.

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
just-bash-website Ready Ready Preview Aug 12, 2026 9:10am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
just-bash Ignored Ignored Aug 12, 2026 9:10am

@auto-maintain

auto-maintain Bot commented Aug 12, 2026

Copy link
Copy Markdown

🤖 auto-maintain review

Automated, advisory triage for @privatenumber's PR. Facts below are read from the GitHub API.

Check Result
Author's merged PRs (this repo) 11
Account established ✅ (age 5436d · 3940 followers · 268 public repos)
Commits signed/verified ✅ 9/9
Changeset included ✅ (.changeset/leading-ifs-array-defaults.md)

Review panel: 🟡 medium highest severity

just-bash maintainer code review: 🟡 medium

The leading-boundary fix leaves the symmetric preceding-expansion boundary case broken for mixed operation words.

  • packages/just-bash/src/interpreter/expansion/word-split.ts:342 — A trailing IFS boundary from the preceding expansion is discarded when the next segment is a mixed parameter-operation word: `pendingWordBreak` is never consumed before combining `split.words` and is overwritten here. For example, with `a='x '; b=y; unset v`, `set -- $a${v:-""$b}` incorrectly merges the arguments as `xy` instead of producing `x` and `y`.

General code review: 🟡 medium

The boundary fix introduces an actionable regression for mixed operation words containing an empty expansion after a trailing IFS delimiter.

  • packages/just-bash/src/interpreter/expansion/word-split.ts:505 — A trailing IFS boundary is lost when followed by an empty unquoted expansion inside a mixed operation word. For example, with `x='b '`, `empty=''`, and unset `value`, `set -- prefix=${value:-$x$empty}suffix` should produce `prefix=b` and `suffix`, but this pre-flush clears `pendingWordBreak`; the empty segment does not restore it, so the helper returns `['b']` without a trailing-boundary marker and the outer splitter merges everything into `prefix=bsuffix`.

Adversarial security: 🟢 low

No actionable adversarial security issues found in the complete diff.

Adversarial security (second opinion): 🟡 medium

No security concerns: the diff is a self-contained word-splitting fidelity fix (no new deps, network, process execution, filesystem or argument-sanitization surface), and the spec-test edit only gates an OSH-specific `shopt` and asserts empty stderr; the one actionable issue is that the new IFS-boundary flush is not applied in the mixed default-value expansion branch, leaving arguments merged in that case.

  • packages/just-bash/src/interpreter/expansion/word-split.ts:313 — The new pending-word-break flush was added to the plain splittable branch (line 346) and to the inner splitter (line 505), but not to the `preparedOperationWord` branch. When a preceding unquoted expansion ended with an IFS delimiter and the next segment is a mixed-quoting default expansion, the pending boundary is silently swallowed: `x='b '; unset v; set -- a$x${v:-"c"d}` yields one argument `abcd` instead of bash's two (`ab`, `cd`). Adding the same `if (pendingWordBreak && currentWord !== "")` flush before computing `flushedLeadingDelimiter` here would make the three branches consistent.

Standard Bash and host portability: 🟢 low

No Bash compatibility or ordinary-host portability issues found.

Posted by auto-maintain. This automated code review is advisory; a human maintainer makes the call.

Comment thread packages/just-bash/src/interpreter/expansion/word-split.ts Outdated
…valuation' into fix/leading-ifs-word-splitting
@auto-maintain

auto-maintain Bot commented Aug 12, 2026

Copy link
Copy Markdown

⚠️ auto-maintain: review severity raised to 🟡 medium

A new push changed this PR and the review now contains a higher-severity finding. See the updated review comment above.

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

In smartWordSplitWithUnquotedLiterals, a quoted prefix followed by a splittable segment that starts with an IFS char produces a spurious empty argument (e.g. with IFS=_ yields ["q","","a"] instead of ["q","a"]).

Fix on Vercel

…valuation' into fix/leading-ifs-word-splitting
…valuation' into fix/leading-ifs-word-splitting
…valuation' into fix/leading-ifs-word-splitting
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.

1 participant