Merge pull request #37134 from thaJeztah/fix-env-substitution
builder: fix processing of invalid substitusion syntax
This commit is contained in:
commit
b2719e35f5
|
@ -18,7 +18,6 @@ A|'hello\there' | hello\there
|
||||||
A|'hello\\there' | hello\\there
|
A|'hello\\there' | hello\\there
|
||||||
A|"''" | ''
|
A|"''" | ''
|
||||||
A|$. | $.
|
A|$. | $.
|
||||||
A|$1 |
|
|
||||||
A|he$1x | hex
|
A|he$1x | hex
|
||||||
A|he$.x | he$.x
|
A|he$.x | he$.x
|
||||||
# Next one is different on Windows as $pwd==$PWD
|
# Next one is different on Windows as $pwd==$PWD
|
||||||
|
@ -29,10 +28,14 @@ A|he\$PWD | he$PWD
|
||||||
A|he\\$PWD | he\/home
|
A|he\\$PWD | he\/home
|
||||||
A|"he\$PWD" | he$PWD
|
A|"he\$PWD" | he$PWD
|
||||||
A|"he\\$PWD" | he\/home
|
A|"he\\$PWD" | he\/home
|
||||||
|
A|\${} | ${}
|
||||||
|
A|\${}aaa | ${}aaa
|
||||||
A|he\${} | he${}
|
A|he\${} | he${}
|
||||||
A|he\${}xx | he${}xx
|
A|he\${}xx | he${}xx
|
||||||
A|he${} | he
|
A|${} | error
|
||||||
A|he${}xx | hexx
|
A|${}aaa | error
|
||||||
|
A|he${} | error
|
||||||
|
A|he${}xx | error
|
||||||
A|he${hi} | he
|
A|he${hi} | he
|
||||||
A|he${hi}xx | hexx
|
A|he${hi}xx | hexx
|
||||||
A|he${PWD} | he/home
|
A|he${PWD} | he/home
|
||||||
|
@ -88,8 +91,8 @@ A|안녕\$PWD | 안녕$PWD
|
||||||
A|안녕\\$PWD | 안녕\/home
|
A|안녕\\$PWD | 안녕\/home
|
||||||
A|안녕\${} | 안녕${}
|
A|안녕\${} | 안녕${}
|
||||||
A|안녕\${}xx | 안녕${}xx
|
A|안녕\${}xx | 안녕${}xx
|
||||||
A|안녕${} | 안녕
|
A|안녕${} | error
|
||||||
A|안녕${}xx | 안녕xx
|
A|안녕${}xx | error
|
||||||
A|안녕${hi} | 안녕
|
A|안녕${hi} | 안녕
|
||||||
A|안녕${hi}xx | 안녕xx
|
A|안녕${hi}xx | 안녕xx
|
||||||
A|안녕${PWD} | 안녕/home
|
A|안녕${PWD} | 안녕/home
|
||||||
|
@ -119,3 +122,111 @@ A|안녕${XXX:-\$PWD:}xx | 안녕$PWD:xx
|
||||||
A|안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
A|안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
||||||
A|$KOREAN | 한국어
|
A|$KOREAN | 한국어
|
||||||
A|안녕$KOREAN | 안녕한국어
|
A|안녕$KOREAN | 안녕한국어
|
||||||
|
A|${{aaa} | error
|
||||||
|
A|${aaa}} | }
|
||||||
|
A|${aaa | error
|
||||||
|
A|${{aaa:-bbb} | error
|
||||||
|
A|${aaa:-bbb}} | bbb}
|
||||||
|
A|${aaa:-bbb | error
|
||||||
|
A|${aaa:-bbb} | bbb
|
||||||
|
A|${aaa:-${bbb:-ccc}} | ccc
|
||||||
|
A|${aaa:-bbb ${foo} | error
|
||||||
|
A|${aaa:-bbb {foo} | bbb {foo
|
||||||
|
A|${:} | error
|
||||||
|
A|${:-bbb} | error
|
||||||
|
A|${:+bbb} | error
|
||||||
|
|
||||||
|
# Positional parameters won't be set:
|
||||||
|
# http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_01
|
||||||
|
A|$1 |
|
||||||
|
A|${1} |
|
||||||
|
A|${1:+bbb} |
|
||||||
|
A|${1:-bbb} | bbb
|
||||||
|
A|$2 |
|
||||||
|
A|${2} |
|
||||||
|
A|${2:+bbb} |
|
||||||
|
A|${2:-bbb} | bbb
|
||||||
|
A|$3 |
|
||||||
|
A|${3} |
|
||||||
|
A|${3:+bbb} |
|
||||||
|
A|${3:-bbb} | bbb
|
||||||
|
A|$4 |
|
||||||
|
A|${4} |
|
||||||
|
A|${4:+bbb} |
|
||||||
|
A|${4:-bbb} | bbb
|
||||||
|
A|$5 |
|
||||||
|
A|${5} |
|
||||||
|
A|${5:+bbb} |
|
||||||
|
A|${5:-bbb} | bbb
|
||||||
|
A|$6 |
|
||||||
|
A|${6} |
|
||||||
|
A|${6:+bbb} |
|
||||||
|
A|${6:-bbb} | bbb
|
||||||
|
A|$7 |
|
||||||
|
A|${7} |
|
||||||
|
A|${7:+bbb} |
|
||||||
|
A|${7:-bbb} | bbb
|
||||||
|
A|$8 |
|
||||||
|
A|${8} |
|
||||||
|
A|${8:+bbb} |
|
||||||
|
A|${8:-bbb} | bbb
|
||||||
|
A|$9 |
|
||||||
|
A|${9} |
|
||||||
|
A|${9:+bbb} |
|
||||||
|
A|${9:-bbb} | bbb
|
||||||
|
A|$999 |
|
||||||
|
A|${999} |
|
||||||
|
A|${999:+bbb} |
|
||||||
|
A|${999:-bbb} | bbb
|
||||||
|
A|$999aaa | aaa
|
||||||
|
A|${999}aaa | aaa
|
||||||
|
A|${999:+bbb}aaa | aaa
|
||||||
|
A|${999:-bbb}aaa | bbbaaa
|
||||||
|
A|$001 |
|
||||||
|
A|${001} |
|
||||||
|
A|${001:+bbb} |
|
||||||
|
A|${001:-bbb} | bbb
|
||||||
|
A|$001aaa | aaa
|
||||||
|
A|${001}aaa | aaa
|
||||||
|
A|${001:+bbb}aaa | aaa
|
||||||
|
A|${001:-bbb}aaa | bbbaaa
|
||||||
|
|
||||||
|
# Special parameters won't be set in the Dockerfile:
|
||||||
|
# http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02
|
||||||
|
A|$@ |
|
||||||
|
A|${@} |
|
||||||
|
A|${@:+bbb} |
|
||||||
|
A|${@:-bbb} | bbb
|
||||||
|
A|$@@@ | @@
|
||||||
|
A|$@aaa | aaa
|
||||||
|
A|${@}aaa | aaa
|
||||||
|
A|${@:+bbb}aaa | aaa
|
||||||
|
A|${@:-bbb}aaa | bbbaaa
|
||||||
|
A|$* |
|
||||||
|
A|${*} |
|
||||||
|
A|${*:+bbb} |
|
||||||
|
A|${*:-bbb} | bbb
|
||||||
|
A|$# |
|
||||||
|
A|${#} |
|
||||||
|
A|${#:+bbb} |
|
||||||
|
A|${#:-bbb} | bbb
|
||||||
|
A|$? |
|
||||||
|
A|${?} |
|
||||||
|
A|${?:+bbb} |
|
||||||
|
A|${?:-bbb} | bbb
|
||||||
|
A|$- |
|
||||||
|
A|${-} |
|
||||||
|
A|${-:+bbb} |
|
||||||
|
A|${-:-bbb} | bbb
|
||||||
|
A|$$ |
|
||||||
|
A|${$} |
|
||||||
|
A|${$:+bbb} |
|
||||||
|
A|${$:-bbb} | bbb
|
||||||
|
A|$! |
|
||||||
|
A|${!} |
|
||||||
|
A|${!:+bbb} |
|
||||||
|
A|${!:-bbb} | bbb
|
||||||
|
A|$0 |
|
||||||
|
A|${0} |
|
||||||
|
A|${0:+bbb} |
|
||||||
|
A|${0:-bbb} | bbb
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
|
||||||
|
|
||||||
if stopChar != scanner.EOF && ch == stopChar {
|
if stopChar != scanner.EOF && ch == stopChar {
|
||||||
sw.scanner.Next()
|
sw.scanner.Next()
|
||||||
break
|
return result.String(), words.getWords(), nil
|
||||||
}
|
}
|
||||||
if fn, ok := charFuncMapping[ch]; ok {
|
if fn, ok := charFuncMapping[ch]; ok {
|
||||||
// Call special processing func for certain chars
|
// Call special processing func for certain chars
|
||||||
|
@ -166,7 +166,9 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
|
||||||
result.WriteRune(ch)
|
result.WriteRune(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if stopChar != scanner.EOF {
|
||||||
|
return "", []string{}, errors.Errorf("unexpected end of statement while looking for matching %s", string(stopChar))
|
||||||
|
}
|
||||||
return result.String(), words.getWords(), nil
|
return result.String(), words.getWords(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,22 +261,29 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.scanner.Next()
|
sw.scanner.Next()
|
||||||
name := sw.processName()
|
switch sw.scanner.Peek() {
|
||||||
ch := sw.scanner.Peek()
|
case scanner.EOF:
|
||||||
if ch == '}' {
|
return "", errors.New("syntax error: missing '}'")
|
||||||
// Normal ${xx} case
|
case '{', '}', ':':
|
||||||
sw.scanner.Next()
|
// Invalid ${{xx}, ${:xx}, ${:}. ${} case
|
||||||
return sw.getEnv(name), nil
|
return "", errors.New("syntax error: bad substitution")
|
||||||
}
|
}
|
||||||
if ch == ':' {
|
name := sw.processName()
|
||||||
|
ch := sw.scanner.Next()
|
||||||
|
switch ch {
|
||||||
|
case '}':
|
||||||
|
// Normal ${xx} case
|
||||||
|
return sw.getEnv(name), nil
|
||||||
|
case ':':
|
||||||
// Special ${xx:...} format processing
|
// Special ${xx:...} format processing
|
||||||
// Yes it allows for recursive $'s in the ... spot
|
// Yes it allows for recursive $'s in the ... spot
|
||||||
|
|
||||||
sw.scanner.Next() // skip over :
|
|
||||||
modifier := sw.scanner.Next()
|
modifier := sw.scanner.Next()
|
||||||
|
|
||||||
word, _, err := sw.processStopOn('}')
|
word, _, err := sw.processStopOn('}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if sw.scanner.Peek() == scanner.EOF {
|
||||||
|
return "", errors.New("syntax error: missing '}'")
|
||||||
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +319,14 @@ func (sw *shellWord) processName() string {
|
||||||
for sw.scanner.Peek() != scanner.EOF {
|
for sw.scanner.Peek() != scanner.EOF {
|
||||||
ch := sw.scanner.Peek()
|
ch := sw.scanner.Peek()
|
||||||
if name.Len() == 0 && unicode.IsDigit(ch) {
|
if name.Len() == 0 && unicode.IsDigit(ch) {
|
||||||
|
for sw.scanner.Peek() != scanner.EOF && unicode.IsDigit(sw.scanner.Peek()) {
|
||||||
|
// Keep reading until the first non-digit character, or EOF
|
||||||
|
ch = sw.scanner.Next()
|
||||||
|
name.WriteRune(ch)
|
||||||
|
}
|
||||||
|
return name.String()
|
||||||
|
}
|
||||||
|
if name.Len() == 0 && isSpecialParam(ch) {
|
||||||
ch = sw.scanner.Next()
|
ch = sw.scanner.Next()
|
||||||
return string(ch)
|
return string(ch)
|
||||||
}
|
}
|
||||||
|
@ -323,6 +340,18 @@ func (sw *shellWord) processName() string {
|
||||||
return name.String()
|
return name.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSpecialParam checks if the provided character is a special parameters,
|
||||||
|
// as defined in http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02
|
||||||
|
func isSpecialParam(char rune) bool {
|
||||||
|
switch char {
|
||||||
|
case '@', '*', '#', '?', '-', '$', '!', '0':
|
||||||
|
// Special parameters
|
||||||
|
// http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (sw *shellWord) getEnv(name string) string {
|
func (sw *shellWord) getEnv(name string) string {
|
||||||
for _, env := range sw.envs {
|
for _, env := range sw.envs {
|
||||||
i := strings.Index(env, "=")
|
i := strings.Index(env, "=")
|
||||||
|
|
|
@ -26,13 +26,11 @@ func TestShellParser4EnvVars(t *testing.T) {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
lineCount++
|
lineCount++
|
||||||
|
|
||||||
// Trim comments and blank lines
|
// Skip comments and blank lines
|
||||||
i := strings.Index(line, "#")
|
if strings.HasPrefix(line, "#") {
|
||||||
if i >= 0 {
|
continue
|
||||||
line = line[:i]
|
|
||||||
}
|
}
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
if line == "" {
|
if line == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -53,10 +51,10 @@ func TestShellParser4EnvVars(t *testing.T) {
|
||||||
((platform == "U" || platform == "A") && runtime.GOOS != "windows") {
|
((platform == "U" || platform == "A") && runtime.GOOS != "windows") {
|
||||||
newWord, err := shlex.ProcessWord(source, envs)
|
newWord, err := shlex.ProcessWord(source, envs)
|
||||||
if expected == "error" {
|
if expected == "error" {
|
||||||
assert.Check(t, is.ErrorContains(err, ""))
|
assert.Check(t, is.ErrorContains(err, ""), "input: %q, result: %q", source, newWord)
|
||||||
} else {
|
} else {
|
||||||
assert.Check(t, err)
|
assert.Check(t, err, "at line %d of %s", lineCount, fn)
|
||||||
assert.Check(t, is.Equal(newWord, expected))
|
assert.Check(t, is.Equal(newWord, expected), "at line %d of %s", lineCount, fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue