From 2c76a0a2fb660772bd692f5c17fb0d2a717d3679 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 17 Apr 2024 16:10:51 -0400 Subject: [PATCH 1/3] don't marshal integer values as msgpack floats Round-tripping a large integer through a float64, even if the binary representation is exact, causes us to end up with a rounded string representation after decoding, because the decoded number has 52-bit precision instead of the 512 we use when dealing with string representations of large integers. --- tftypes/value_msgpack.go | 2 +- tftypes/value_msgpack_test.go | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tftypes/value_msgpack.go b/tftypes/value_msgpack.go index ed03ef983..08fb15207 100644 --- a/tftypes/value_msgpack.go +++ b/tftypes/value_msgpack.go @@ -446,7 +446,7 @@ func marshalMsgPackNumber(val Value, typ Type, p *AttributePath, enc *msgpack.En if err != nil { return p.NewErrorf("error encoding int value: %w", err) } - } else if fv, acc := n.Float64(); acc == big.Exact { + } else if fv, acc := n.Float64(); acc == big.Exact && !n.IsInt() { err := enc.EncodeFloat64(fv) if err != nil { return p.NewErrorf("error encoding float value: %w", err) diff --git a/tftypes/value_msgpack_test.go b/tftypes/value_msgpack_test.go index d4392a32d..778c073e1 100644 --- a/tftypes/value_msgpack_test.go +++ b/tftypes/value_msgpack_test.go @@ -27,6 +27,10 @@ func TestValueFromMsgPack(t *testing.T) { if err != nil { t.Fatalf("error parsing awkward fraction: %s", err) } + + // integer under 64 bits which rounds incorrectly if parsed as a float64 + uint64AsFloat, _ := new(big.Float).SetString("9223372036854775808") + tests := map[string]testCase{ "hello-string": { hex: "a568656c6c6f", @@ -94,7 +98,8 @@ func TestValueFromMsgPack(t *testing.T) { typ: Number, }, "float64-positive-number": { - hex: "cb7fefffffffffffff", + // Because MaxFloat64 is an integer value, it must be encoded as an integer to ensure we don't lose precision when decoding the value + hex: "da0135313739373639333133343836323331353730303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030", value: NewValue(Number, new(big.Float).SetFloat64(math.MaxFloat64)), typ: Number, }, @@ -123,6 +128,11 @@ func TestValueFromMsgPack(t *testing.T) { value: NewValue(Number, big.NewFloat(math.Inf(-1))), typ: Number, }, + "large-uint64": { + hex: "b339323233333732303336383534373735383038", + value: NewValue(Number, uint64AsFloat), + typ: Number, + }, "dynamic-bool": { hex: "92c40622626f6f6c22c3", value: NewValue(Bool, true), @@ -545,8 +555,8 @@ func TestValueFromMsgPack(t *testing.T) { t.Fatalf("unexpected error unmarshaling: %s", err) } - if diff := cmp.Diff(test.value, val); diff != "" { - t.Errorf("Unexpected results (-wanted +got): %s", diff) + if test.value.String() != val.String() { + t.Errorf("Unexpected results (-wanted +got): %s", cmp.Diff(test.value, val)) } }) } From e766d1b64617d8eaa82c083ef7467f55035c10cc Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 18 Apr 2024 12:10:26 -0400 Subject: [PATCH 2/3] update CHANGELOG.md --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecc185c74..32468ca1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.22.2 (Unreleased) + +BUG FIXES: + +* tftypes: Large integers are always encoded as msgpack integers rather than float values to ensure the decoded value will not be rounded to 52-bit precision ([#396](https://github.com/hashicorp/terraform-plugin-go/pull/396)) + + ## 0.22.1 (March 11, 2024) NOTES: From e2c18d40b2a4e906e698d06ad90fafcdb1f5c634 Mon Sep 17 00:00:00 2001 From: Austin Valle Date: Thu, 18 Apr 2024 12:18:41 -0400 Subject: [PATCH 3/3] update to changie log --- .changes/unreleased/BUG FIXES-20240418-121811.yaml | 6 ++++++ CHANGELOG.md | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 .changes/unreleased/BUG FIXES-20240418-121811.yaml diff --git a/.changes/unreleased/BUG FIXES-20240418-121811.yaml b/.changes/unreleased/BUG FIXES-20240418-121811.yaml new file mode 100644 index 000000000..a7c36ad99 --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20240418-121811.yaml @@ -0,0 +1,6 @@ +kind: BUG FIXES +body: 'tftypes: Large integers are always encoded as msgpack integers rather than + float values to ensure the decoded value will not be rounded to 52-bit precision' +time: 2024-04-18T12:18:11.880247-04:00 +custom: + Issue: "396" diff --git a/CHANGELOG.md b/CHANGELOG.md index 32468ca1b..ecc185c74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,3 @@ -## 0.22.2 (Unreleased) - -BUG FIXES: - -* tftypes: Large integers are always encoded as msgpack integers rather than float values to ensure the decoded value will not be rounded to 52-bit precision ([#396](https://github.com/hashicorp/terraform-plugin-go/pull/396)) - - ## 0.22.1 (March 11, 2024) NOTES: