From c8f22cd1c9439bc07a1e08f1c621886803d00ddc Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 17 Aug 2021 13:07:37 -0400 Subject: [PATCH] cty: AsBigFloat must make a deep copy Use Float.Copy in AsBigFloat to ensure that there is no shared data between the mutable *big.Float and the cty.Value internal state. big.Float includes some pointers, so a shallow copy is insufficient. --- cty/value_ops.go | 4 +--- cty/value_ops_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cty/value_ops.go b/cty/value_ops.go index 17afd8d8..55bebe03 100644 --- a/cty/value_ops.go +++ b/cty/value_ops.go @@ -1283,9 +1283,7 @@ func (val Value) AsBigFloat() *big.Float { } // Copy the float so that callers can't mutate our internal state - ret := *(val.v.(*big.Float)) - - return &ret + return new(big.Float).Copy(val.v.(*big.Float)) } // AsValueSlice returns a []cty.Value representation of a non-null, non-unknown diff --git a/cty/value_ops_test.go b/cty/value_ops_test.go index c6f8b94d..39f5f765 100644 --- a/cty/value_ops_test.go +++ b/cty/value_ops_test.go @@ -3442,3 +3442,16 @@ func TestHasWhollyKnownType(t *testing.T) { }) } } + +func TestFloatCopy(t *testing.T) { + // ensure manipulating floats does not modify the cty.Value + v := NumberFloatVal(1.9) + vString := v.GoString() + + // do something that will modify the internal big.Float mantissa + v.AsBigFloat().SetInt64(1) + + if vString != v.GoString() { + t.Fatalf("original value changed from %s to %#v", vString, v) + } +}