Skip to content

executor: a backquoted body inside double quotes unescapes " (#743) - #747

Merged
berrym merged 1 commit into
masterfrom
fix/743-backtick-escaped-quote
Aug 16, 2026
Merged

executor: a backquoted body inside double quotes unescapes " (#743)#747
berrym merged 1 commit into
masterfrom
fix/743-backtick-escaped-quote

Conversation

@berrym

@berrym berrym commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Closes #743.

The rule is context-dependent

POSIX 2.6.3 gives the backquoted form an escape set that depends on where it appears: a backslash is special before $, a backtick or another backslash — and before " as well when the backquoted form is inside double quotes.

#732 implemented the three-character set. That is correct unquoted, where lush and every peer already agreed, but incomplete inside double quotes:

$ lush -c 'echo "pre`printf \"a b\"`post"'
pre"apost                       # bash, dash: prea bpost

It was never truncation

The issue (which I filed) described this as the word being truncated. It is not. The \" survived into the body, so the sub-parse saw printf \"a b\" and passed printf two arguments — "a and b" — of which printf rendered only the first. Unescaping the quote makes it a real quote delimiter, so the body passes one argument. That is the entire difference.

The context is carried, not guessed

expand_quoted_string_prov already has an in_double_quotes parameter for exactly this kind of question, and its three callers already pass it correctly (true for a double-quoted word, false for a subscript key). It is threaded to lush_backtick_unescape through a new expand_command_substitution_ex; the old name remains as the unquoted-context wrapper, so no other call site changes.

$( ) deliberately does not take the rule

Its body is a fresh command, so \" keeps its backslash even inside double quotes:

$ lush -c 'echo "pre$(printf \"a b\")post"'
pre"apost                       # bash, dash: identical

lush already matched both peers here. The test pins it so the two forms cannot be conflated later.

Verification

  • 5 new checks in tests/integration/test_nested_backticks.c: the reported case, the same without surrounding literals, a single-word body unaffected either way, the unquoted form that must keep its backslash, and the $( ) form that must not take the rule.
  • 3 of the file's 34 checks fail against the parent build, with a control proving the binaries differ.
  • Full suite 195/195. ASan 65/65 and the backtick test 1/1 under ASan — both run with the repaired asan-check, whose worktree sync had been silently stale earlier today.

POSIX 2.6.3 gives the backquoted form a context-dependent escape set. A
backslash is special before `$`, a backtick or another backslash -- and,
when the backquoted form appears INSIDE double quotes, before `"` as well.

#732 implemented the three-character set. That is right unquoted, where lush
and every peer already agreed, but incomplete inside double quotes:

    echo "pre`printf \"a b\"`post"
      before: pre"apost        bash, dash: prea bpost

The visible symptom looked like truncation, and the issue described it that
way. It is not. The `\"` survived into the body, so the sub-parse saw
`printf \"a b\"` and passed printf TWO arguments -- `"a` and `b"` -- of which
printf rendered only the first. Unescaping the quote makes it a real quote
delimiter, so the body passes ONE argument, which is the whole difference.

The context is not guessed at: expand_quoted_string_prov already carries
in_double_quotes for exactly this kind of question, and its three callers
already pass it correctly (true for a double-quoted word, false for a
subscript key). It is threaded to lush_backtick_unescape through a new
expand_command_substitution_ex; the old name stays as the unquoted-context
wrapper, so no other call site changes.

`$( )` deliberately does NOT take the rule: its body is a fresh command and a
`\"` inside it keeps its backslash even within double quotes. lush already
matched bash and dash there, and the test pins it so the two forms cannot be
conflated later.

tests/integration/test_nested_backticks.c gains 5 checks: the reported case,
the same without surrounding literals, a single-word body that is unaffected
either way, the unquoted form that must KEEP its backslash, and the `$( )`
form that must not take the rule. 3 of the file's 34 checks fail against the
parent build.
@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@berrym
berrym merged commit 5b39eb5 into master Aug 16, 2026
7 checks passed
@berrym
berrym deleted the fix/743-backtick-escaped-quote branch August 16, 2026 11:13
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.

an escaped double quote inside a backtick substitution inside double quotes truncates the word

1 participant