executor: a backquoted body inside double quotes unescapes " (#743) - #747
Merged
Conversation
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 Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
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 sawprintf \"a b\"and passed printf two arguments —"aandb"— 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_provalready has anin_double_quotesparameter for exactly this kind of question, and its three callers already pass it correctly (truefor a double-quoted word,falsefor a subscript key). It is threaded tolush_backtick_unescapethrough a newexpand_command_substitution_ex; the old name remains as the unquoted-context wrapper, so no other call site changes.$( )deliberately does not take the ruleIts body is a fresh command, so
\"keeps its backslash even inside double quotes:lush already matched both peers here. The test pins it so the two forms cannot be conflated later.
Verification
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.asan-check, whose worktree sync had been silently stale earlier today.