Skip to content

Commit de6f76c

Browse files
alisdairbbasata
authored andcommitted
stdlib: Fix set function crashes with empty sets
If one or more arguments to the stdlib set functions was an empty set of dynamic pseudo type, the functions would panic due to incompatible set rules. We can special case empty dynamic pseudo type sets to be ignored through type unification, because they are always capable of being converted to any other type.
1 parent a716a21 commit de6f76c

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

cty/function/stdlib/set.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,23 @@ func SetSymmetricDifference(sets ...cty.Value) (cty.Value, error) {
163163
func setOperationReturnType(args []cty.Value) (ret cty.Type, err error) {
164164
var etys []cty.Type
165165
for _, arg := range args {
166-
etys = append(etys, arg.Type().ElementType())
166+
ty := arg.Type().ElementType()
167+
168+
// Do not unify types for empty dynamic pseudo typed collections. These
169+
// will always convert to any other concrete type.
170+
if arg.LengthInt() == 0 && ty.Equals(cty.DynamicPseudoType) {
171+
continue
172+
}
173+
174+
etys = append(etys, ty)
167175
}
176+
177+
// If all element types were skipped (due to being empty dynamic collections),
178+
// the return type should also be a set of dynamic pseudo type.
179+
if len(etys) == 0 {
180+
return cty.Set(cty.DynamicPseudoType), nil
181+
}
182+
168183
newEty, _ := convert.UnifyUnsafe(etys)
169184
if newEty == cty.NilType {
170185
return cty.NilType, fmt.Errorf("given sets must all have compatible element types")

cty/function/stdlib/set_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ func TestSetUnion(t *testing.T) {
5555
cty.StringVal("c"),
5656
}),
5757
},
58+
{
59+
[]cty.Value{
60+
cty.SetVal([]cty.Value{cty.True}),
61+
cty.SetValEmpty(cty.DynamicPseudoType),
62+
},
63+
cty.SetVal([]cty.Value{cty.True}),
64+
},
65+
{
66+
[]cty.Value{
67+
cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
68+
cty.SetValEmpty(cty.DynamicPseudoType),
69+
},
70+
cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
71+
},
72+
{
73+
[]cty.Value{
74+
cty.SetValEmpty(cty.DynamicPseudoType),
75+
cty.SetValEmpty(cty.DynamicPseudoType),
76+
},
77+
cty.SetValEmpty(cty.DynamicPseudoType),
78+
},
5879
}
5980

6081
for _, test := range tests {
@@ -117,6 +138,27 @@ func TestSetIntersection(t *testing.T) {
117138
cty.StringVal("b"),
118139
}),
119140
},
141+
{
142+
[]cty.Value{
143+
cty.SetVal([]cty.Value{cty.True}),
144+
cty.SetValEmpty(cty.DynamicPseudoType),
145+
},
146+
cty.SetValEmpty(cty.Bool),
147+
},
148+
{
149+
[]cty.Value{
150+
cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
151+
cty.SetValEmpty(cty.DynamicPseudoType),
152+
},
153+
cty.SetValEmpty(cty.EmptyObject),
154+
},
155+
{
156+
[]cty.Value{
157+
cty.SetValEmpty(cty.DynamicPseudoType),
158+
cty.SetValEmpty(cty.DynamicPseudoType),
159+
},
160+
cty.SetValEmpty(cty.DynamicPseudoType),
161+
},
120162
}
121163

122164
for _, test := range tests {
@@ -169,6 +211,21 @@ func TestSetSubtract(t *testing.T) {
169211
cty.StringVal("b"),
170212
}),
171213
},
214+
{
215+
cty.SetVal([]cty.Value{cty.StringVal("a")}),
216+
cty.SetValEmpty(cty.DynamicPseudoType),
217+
cty.SetVal([]cty.Value{cty.StringVal("a")}),
218+
},
219+
{
220+
cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
221+
cty.SetValEmpty(cty.DynamicPseudoType),
222+
cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
223+
},
224+
{
225+
cty.SetValEmpty(cty.DynamicPseudoType),
226+
cty.SetValEmpty(cty.DynamicPseudoType),
227+
cty.SetValEmpty(cty.DynamicPseudoType),
228+
},
172229
}
173230

174231
for _, test := range tests {

0 commit comments

Comments
 (0)