syntax: honor escaped brace metacharacters#1330
syntax: honor escaped brace metacharacters#1330AlexandreYang wants to merge 1 commit intomvdan:masterfrom
Conversation
bc5d4bd to
e3d1bbe
Compare
|
Downstream context: this bash-compatibility issue was found while updating DataDog/rshell to mvdan.cc/sh/v3 v3.13.1: DataDog/rshell#197 rshell currently carries a local workaround before calling |
|
Hello ! |
|
Thanks, I'll take a look at this this weekend. It's likely that there is a bug here, but I don't think this fix is the right approach. |
|
The fix is now in master; as expected this was almost a one-line fix. The apparent regression was 7e3be04; note how the I'll probably tag a bugfix release in the coming days. |
|
Thanks a lot! |
|
Thanks for fixing so quickly! Would it be possible to have a new release ? |
|
As I already mentioned, I'll tag a release in a few days. You can use master in the meantime. |
cc @mvdan
Summary
syntax.SplitBracescurrently scans literal word parts for{,,,.., and}without checking whether those bytes were quoted with a backslash. Bash performs brace expansion before quote removal, but brace syntax is still made of unquoted metacharacters: an unquoted opening brace, an unquoted comma or sequence expression, and an unquoted closing brace.As a result,
expand.Fieldscan produce fields that differ from bash for words such as:\{a,b}: the{is quoted, so this should stay one field:{a,b}{a\,b,c}: the comma is quoted, so this should expand toa,bandc{a\}b,c}: the first}is quoted, so this should expand toa}bandc\{{x},z}: the first{is quoted, but the later brace expression should still be parsed like bashThis PR updates
SplitBracesto ignore backslash-escaped brace metacharacters. It also keeps a top-level single-element brace open long enough for a later unescaped comma or sequence operator to form an expansion, which is needed for bash-compatible cases like{x},z}and\{{x},z}.The actual expansion enumerator,
expand.Braces, is unchanged; this only changes howsyntax.SplitBracesidentifiesBraceExpnodes.Why this is needed
expand.Fieldsis commonly used as the high-level shell field expansion API. Callers expect it to be close to bash for argument expansion, especially because brace expansion happens before quote removal. Today, callers that need bash-compatible behavior must add their own pre-processing aroundexpand.Fieldsto protect escaped brace metacharacters beforeSplitBracesruns.Fixing this in
SplitBracesis the right layer because:SplitBracesis where literal text is classified as brace syntax or ordinary text.expand.Bracesonly enumerates already-parsedBraceExpnodes; by then it is too late to know that a metacharacter was escaped.*syntax.Litvalues, soSplitBraceshas enough information to distinguish quoted vs unquoted brace metacharacters.Downstream context
This issue was found while updating DataDog/rshell from
mvdan.cc/sh/v3v3.13.0 to v3.13.1: DataDog/rshell#197rshell currently carries a local compatibility shim before calling
expand.Fieldsto preserve bash behavior for escaped brace metacharacters. If this fix lands upstream and is released, rshell should be able to remove most or all of that workaround.Reproducing and comparing with bash
From a checkout of
mvdan/sh, run this Go reproducer:Then run the equivalent bash argv-expansion script:
Compare them:
On
masterbefore this PR, the diff shows multiple mismatches, for example\{a,b}is incorrectly expanded as if the escaped{were brace syntax. With this PR, the diff is empty for these cases.Tests
go test ./syntax ./expand