From e93d69f18b7d3c4449286c1827bcf2bb3de9ecc7 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 19 Oct 2018 16:51:15 -0400 Subject: [PATCH] more nil/known checks before val.LengthInt --- command/format/diff.go | 2 +- plans/objchange/compatible.go | 10 +++++----- plans/objchange/objchange.go | 32 ++++++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/command/format/diff.go b/command/format/diff.go index 260c031de..c58661663 100644 --- a/command/format/diff.go +++ b/command/format/diff.go @@ -856,7 +856,7 @@ func ctyGetAttrMaybeNull(val cty.Value, name string) cty.Value { } func ctyCollectionValues(val cty.Value) []cty.Value { - if !val.IsKnown() { + if !val.IsKnown() || val.IsNull() { return nil } diff --git a/plans/objchange/compatible.go b/plans/objchange/compatible.go index 83b717554..8ac80ab05 100644 --- a/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -64,7 +64,7 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu return errs } case configschema.NestingList, configschema.NestingMap, configschema.NestingSet: - if plannedV.IsKnown() && plannedV.LengthInt() == 1 { + if plannedV.IsKnown() && !plannedV.IsNull() && plannedV.LengthInt() == 1 { elemVs := plannedV.AsValueSlice() if allLeafValuesUnknown(elemVs[0]) { return errs @@ -84,7 +84,7 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu // whether there are dynamically-typed attributes inside. However, // both support a similar-enough API that we can treat them the // same for our purposes here. - if !plannedV.IsKnown() { + if !plannedV.IsKnown() || plannedV.IsNull() || actualV.IsNull() { continue } @@ -129,7 +129,7 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu } } } else { - if !plannedV.IsKnown() { + if !plannedV.IsKnown() || plannedV.IsNull() || actualV.IsNull() { continue } plannedL := plannedV.LengthInt() @@ -153,7 +153,7 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu // content is also their key, and so we have no way to correlate // them. Because of this, we simply verify that we still have the // same number of elements. - if !plannedV.IsKnown() { + if !plannedV.IsKnown() || plannedV.IsNull() || actualV.IsNull() { continue } plannedL := plannedV.LengthInt() @@ -251,7 +251,7 @@ func assertValueCompatible(planned, actual cty.Value, path cty.Path) []error { // so we can't correlate them properly. However, we will at least check // to ensure that the number of elements is consistent, along with // the general type-match checks we ran earlier in this function. - if planned.IsKnown() { + if planned.IsKnown() && !planned.IsNull() && !actual.IsNull() { plannedL := planned.LengthInt() actualL := actual.LengthInt() if plannedL < actualL { diff --git a/plans/objchange/objchange.go b/plans/objchange/objchange.go index 5e68a780e..33e82dd52 100644 --- a/plans/objchange/objchange.go +++ b/plans/objchange/objchange.go @@ -92,8 +92,12 @@ func ProposedNewObject(schema *configschema.Block, prior, config cty.Value) cty. case configschema.NestingList: // Nested blocks are correlated by index. - if l := configV.LengthInt(); l > 0 { - newVals := make([]cty.Value, 0, l) + configVLen := 0 + if configV.IsKnown() && !configV.IsNull() { + configVLen = configV.LengthInt() + } + if configVLen > 0 { + newVals := make([]cty.Value, 0, configVLen) for it := configV.ElementIterator(); it.Next(); { idx, configEV := it.Element() if priorV.IsKnown() && (priorV.IsNull() || !priorV.HasIndex(idx).True()) { @@ -130,8 +134,12 @@ func ProposedNewObject(schema *configschema.Block, prior, config cty.Value) cty. // dynamically-typed attributes. if configV.Type().IsObjectType() { // Nested blocks are correlated by key. - if l := configV.LengthInt(); l > 0 { - newVals := make(map[string]cty.Value, l) + configVLen := 0 + if configV.IsKnown() && !configV.IsNull() { + configVLen = configV.LengthInt() + } + if configVLen > 0 { + newVals := make(map[string]cty.Value, configVLen) atys := configV.Type().AttributeTypes() for name := range atys { configEV := configV.GetAttr(name) @@ -154,8 +162,12 @@ func ProposedNewObject(schema *configschema.Block, prior, config cty.Value) cty. newV = cty.EmptyObjectVal } } else { - if l := configV.LengthInt(); l > 0 { - newVals := make(map[string]cty.Value, l) + configVLen := 0 + if configV.IsKnown() && !configV.IsNull() { + configVLen = configV.LengthInt() + } + if configVLen > 0 { + newVals := make(map[string]cty.Value, configVLen) for it := configV.ElementIterator(); it.Next(); { idx, configEV := it.Element() k := idx.AsString() @@ -190,9 +202,13 @@ func ProposedNewObject(schema *configschema.Block, prior, config cty.Value) cty. if priorV.IsKnown() && !priorV.IsNull() { cmpVals = setElementCompareValues(&blockType.Block, priorV, false) } - if l := configV.LengthInt(); l > 0 { + configVLen := 0 + if configV.IsKnown() && !configV.IsNull() { + configVLen = configV.LengthInt() + } + if configVLen > 0 { used := make([]bool, len(cmpVals)) // track used elements in case multiple have the same compare value - newVals := make([]cty.Value, 0, l) + newVals := make([]cty.Value, 0, configVLen) for it := configV.ElementIterator(); it.Next(); { _, configEV := it.Element() var priorEV cty.Value