lang: Fix non-string key panics in map function

The map function assumed that the key arguments were strings, and would
panic if they were not.

After this commit, calling `map(1, 2)` will result in a map `{"1" = 1}`,
and calling `map(null, 1)` will result in a syntax error.

Fixes #23346, fixes #23043
This commit is contained in:
Alisdair McDiarmid 2020-03-04 10:46:14 -05:00
parent 0bd40fd496
commit 37006c5841
2 changed files with 30 additions and 3 deletions

View File

@ -346,12 +346,14 @@ var MapFunc = function.New(&function.Spec{
for i := 0; i < len(args); i += 2 { for i := 0; i < len(args); i += 2 {
key := args[i].AsString() keyVal, err := convert.Convert(args[i], cty.String)
err := gocty.FromCtyValue(args[i], &key)
if err != nil { if err != nil {
return cty.NilVal, err return cty.NilVal, err
} }
if keyVal.IsNull() {
return cty.NilVal, fmt.Errorf("argument %d is a null key", i+1)
}
key := keyVal.AsString()
val := args[i+1] val := args[i+1]

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
) )
func TestLength(t *testing.T) { func TestLength(t *testing.T) {
@ -730,6 +731,19 @@ func TestMap(t *testing.T) {
}), }),
false, false,
}, },
{ // convert number keys to strings
[]cty.Value{
cty.NumberIntVal(1),
cty.StringVal("hello"),
cty.NumberIntVal(2),
cty.StringVal("goodbye"),
},
cty.MapVal(map[string]cty.Value{
"1": cty.StringVal("hello"),
"2": cty.StringVal("goodbye"),
}),
false,
},
{ // map of lists is okay { // map of lists is okay
[]cty.Value{ []cty.Value{
cty.StringVal("hello"), cty.StringVal("hello"),
@ -785,6 +799,14 @@ func TestMap(t *testing.T) {
cty.NilVal, cty.NilVal,
true, true,
}, },
{ // null key returns an error
[]cty.Value{
cty.NullVal(cty.DynamicPseudoType),
cty.NumberIntVal(5),
},
cty.NilVal,
true,
},
} }
for _, test := range tests { for _, test := range tests {
@ -794,6 +816,9 @@ func TestMap(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("succeeded; want error") t.Fatal("succeeded; want error")
} }
if _, ok := err.(function.PanicError); ok {
t.Fatalf("unexpected panic: %s", err)
}
return return
} else if err != nil { } else if err != nil {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)