Skip to content

Reject empty command names in the parser - #2

Merged
carlsverre merged 2 commits into
mainfrom
fix/empty-command-name
Aug 4, 2026
Merged

Reject empty command names in the parser#2
carlsverre merged 2 commits into
mainfrom
fix/empty-command-name

Conversation

@exe-dev-github-integration

Copy link
Copy Markdown

parser::parse returns a Command with an empty name when the first token of a script line is a quoted empty string. The minimal inputs are '' and '' e; the second one parses into Command { name: "", args: ["e"] }. The tokenizer emits empty tokens for quoted empty strings on purpose, because cmd '' must pass an empty argument. But parse_command_line takes the first token (or the token after !) as the command name without a non-empty check. Three fuzz targets (parser, tokens, structured) crash on this input; their assertion that a command name is never empty is a correct invariant, and Go's testscript rejects such lines. The crash surfaced in fuzz run https://github.com/antithesishq/testscript-rs/actions/runs/30781132837.

The fix is in parse_command_line only. When the command-name token is empty, in both the plain case and the ! negation case, the parser now returns a parse error with the line number and the message "empty command name". parse_command_tokens does not change, so empty quoted arguments keep working.

A regression test checks that '' and '' e fail to parse with the empty-command-name error, that "" arg and ! '' fail the same way, and that cmd '' still parses with one empty-string argument. cargo test passes across all suites. A standalone reproducer feeds the fuzz crash inputs through parser::parse and now gets Err(Parse error at line 1: empty command name) for both. cargo fmt --check and cargo clippy --all-targets -- -D warnings pass. cargo-fuzz is not installed in this environment, so the fuzz targets did not run locally.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S9UYm4w97yWTsvMeRHC2uZ

carlsverre and others added 2 commits August 3, 2026 05:24
A script line that starts with a quoted empty string, such as '' or
''  e, parses into a Command with an empty name. The tokenizer emits
empty tokens for quoted empty strings on purpose, because cmd '' must
pass an empty argument. But parse_command_line takes the first token
as the command name without a check.

Return a parse error with the line number when the command-name token
is empty, in both the plain case and the ! negation case. The
tokenizer does not change, so empty quoted arguments still work.

Three fuzz targets (parser, tokens, structured) crash on this input.
See the failing fuzz run 30781132837. A regression test covers the
crash inputs and the still-valid empty-argument case.

Co-Authored-By: Claude <noreply@anthropic.com>
test_update_scripts_via_env_var sets UPDATE_SCRIPTS and then reads it
inside execute(). test_normal_mode_still_fails removes the same
variable on a parallel test thread. The variable is process-global,
so the removal can land between the set and the read. The test then
runs in normal mode and fails, as seen in CI run 30787133800.

Add a shared mutex and hold it for the whole body of both tests. The
lock ignores poisoning, so one failed test does not cascade into the
other. The two other tests in the file set update_scripts explicitly
and never read the variable, so they need no lock.

Co-Authored-By: Claude <noreply@anthropic.com>
@carlsverre
carlsverre merged commit 6ae897b into main Aug 4, 2026
3 checks passed
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